GroovyCodeVisitor says java method returns Object instead of actual type. No generics involved - groovy

I am using a GroovyCodeVisitor to check and complain if banned types are within a script. The visitor sees attempts to new Banned() but when visiting a method that returns Banned it only sees Object. Is this intentional or am i missing something. I just want to confirm the method is a plain vanilla declaration that returns plain old boring Banned and does not included generics in any form which should eliminate erasure as a potential source of the problem.
Before any jumps, I am not using SecureASTCompilationCustsomer because i am using a matcher to ban classes rather than simply adding black and white lists and other stuff which are supported by SecureASTCompilationCustomizer.

GroovyCodeVisitor is for visiting "code". That is for example the body of a Method. The return type of a method is stored in the MethodNode, not the code part you handle with your GroovyCodeVisitor. You could use ClassCodeVisitorSupport and override visitMethod(MethodNode mn) to then get the return type via mn.getReturnType() and give that into your checking code. Of course a method's return type is only for example "Banned" if declared so. If you use "def" for example the return type will be Object.

Related

Is the `def` keyword optional? If so, why use it?

I am aware that a variable can be dynamically typed with the def keyword in Groovy. But I have also noticed that in some circumstances it can be left out, such as when defining method parameters, eg func(p1, p2) instead of func(def p1, def p2). The latter form is discouraged.
I have noticed that this is extendable to all code - anytime you want to define a variable and set its value, eg var = 2 the def keyword can be safely left out. It only appears to be required if not instantiating the variable on creation, ie. def var1 so that it can be instantiated as a NullObject.
Is this the only time def is useful? Can it be safely left out in all other declarations, for example, of classes and methods?
Short answer: you can't. There are some use cases where skipping the type declaration (or def keyword) works, but it is not a general rule. For instance, Groovy scripts allow you to use variables without specific type declaration, e.g.
x = 10
However, it works because groovy.lang.Script class implements getProperty and setProperty methods that get triggered when you access a missing property. In this case, such a variable is promoted to be a global binding, not a local variable. If you try to do the same on any other class that does not implement those methods, you will end up getting groovy.lang.MissingPropertyException.
Skipping types in a method declaration is supported, both in dynamically compiled and statically compiled Groovy. But is it useful? It depends. In most cases, it's much better to declare the type for a better readability and documentation purpose. I would not recommend doing it in the public API - the user of your API will see Object type, while you may expect some specific type. It shows that this may work if your intention is to receive any object, no matter what is its specific type. (E.g. a method like dump(obj) could work like that.)
And last but not least, there is a way to skip type declaration in any context. You can use a final keyword for that.
class Foo {
final id = 1
void bar(final name) {
final greet = "Hello, "
println greet + name + "!"
}
}
This way you can get a code that compiles with dynamic compilation, as well as with static compilation enabled. Of course, using final keyword prevents you from re-assigning the variable, but for the compiler, this is enough information to infer the proper type.
For more information, you can check a similar question that was asked on SO some time ago: Groovy: "def" keyword vs concrete type
in Groovy it plays an important role in Global and Local variable
if the variable name is same with and without def
def is considered local and without def its global
I have explained here in detail https://stackoverflow.com/a/45994227/2986279
So if someone use with and without it will make a difference and can change things.

How to read visual studio code intellisense syntax hint, any document for operators?

VSC like VS gives out syntax/signature hint. I understand : means data type
myText: string // : means datatype of myText is string
myStuff: any // any means can be any data type.
sometimes hard to guess what the operators mean, for example the Node's request(),
my understanding is
const request means I can define any variable like const x=request(...) or var x=request(...).
request.RequestAPI means it's an API call.
options: defines this parameter is a typical object-like options in form of {...}
(request.UriOptions & request.CoreOptions) I understand the beginning and end parts, they must be enum of Uri and Core, but what is &? Does it mean I need to supply both Uri AND Core?
| does this pipe mean OR? If it is then it's duplicating the part before the pipe.
callback?: request.RequestCallback, so here I must provide a callback which will be typed (or functioning) as RequestCallback, but what is ?:?
Is there any document for these conventions?
I wanted to comment, because I don't know the complete answer, but here is some helpful information:
You are probably seeing this definition of DefinitelyTyped: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/request/index.d.ts#L29
Have a look at this to understand the definition file syntax: http://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html
And you can interpret the definition like this:
const request: there is a constant named request that implements the interface request.RequestAPI (which is also callable directly and then for that) takes arguments options of type (request.UriOptions & request.CoreOptions) | (request.UrlOptions & request.CoreOptions) and an optional parameter callback (hence the ? of type request.RequestCallback. The function returns a request.Request.
& usually mean and
A pipe | usually means or, there is no duplication URI vs URL
=> "returns"
You see request in front of everything because it's the namespace (my wording may be off here)
The definitions of UriOptions, UrlOptions, CoreOptions are buried a bit. I'm not a node user, so I don't know what you can pass to request.
For example UrlOptions can either be a string argument named "url" or a url (from require('url')). See https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/request/index.d.ts#L162

Why doesn't calling repr on type objects work as expected?

First, let me say that I agree that eval(repr(some_string)) is potentially a bad idea. But it is a thing that exists, and I have a specific question about it.
Why doesn't this work?
my_type = int
my_type_str = repr(int)
my_type_from_str = eval(my_type_str)
To clarify, I know specifically why the eval call fails. The command repr(int) produces a string which cannot be automatically interpreted. I guess my issue is that this isn't behaving as I expect... so either my expectation is faulty or the implementation is faulty. Which is it?
Side Note
There are some tricks that can be used to get around this default behavior, some obvious, some not. For instance, this:
my_type = int
my_type_str = my_type.__name__
my_type_from_str = eval(my_type_str)
assert my_type is my_type_from_str
This sets off my "hack" alert hardcore, and I don't like it (or other similar hacks, for instance parsing the string "<class 'int'>" with some home made function).
The documentation explains:
Return a string containing a printable representation of an object. For many types, this function makes an attempt to return a string that would yield an object with the same value when passed to eval(), otherwise the representation is a string enclosed in angle brackets that contains the name of the type of the object together with additional information often including the name and address of the object. A class can control what this function returns for its instances by defining a repr() method.
(emphasis mine)
So, it doesn't say that repr must always return valid Python code - sometimes it's not the case. Just another argument for not relying on it.

what does getType do in antlr4?

This question is with reference to the Cymbol code from the book (~ page 143) :
int t = ctx.type().start.getType(); // in DefPhase.enterFunctionDecl()
Symbol.Type type = CheckSymbols.getType(t);
What does each component return: "ctx.type()", "start", "getType()" ? The book does not contain any explanation about these names.
I can "kind of" understand that "ctx.type()" refers to the "type" rule, and "getType()" returns the number associated with it. But what exactly does the "start" do?
Also, to generalize this question: what is the mechanism to get the value/structure returned by a rule - especially in the context of usage in a listener?
I can see that for an ID, it is:
String name = ctx.ID().getText();
And as in above, for an enumeration of keywords it is via "start.getType()". Any other special kinds of access that I should be aware of?
Lets disassemble problem step by step. Obviously, ctx is instance of CymbolParser.FunctionDeclContext. On page 98-99 you can see how grammar and ParseTree are implemented (at least the feeling - for real implementation please see th .g4 file).
Take a look at the figure of AST on page 99 - you can see that node FunctionDeclContext has a several children, one labeled type. Intuitively you see that it somehow correspond with function return-type. This is the node you retrieve when calling CymbolParser.FunctionDeclContext::type. The return type is probably sth like TypeContext.
Note that methods without 'get' at the beginning are usually children-getters - e.g. you can access the block by calling CymbolParser.FunctionDeclContext::block.
So you got the type context of the method you got passed. You can call either begin or end on any context to get first of last Token defining the context. Simply start gets you "the first word". In this case, the first Token is of course the function return-type itsef, e.g. int.
And the last call - Token::getType returns integral representation of Token.
You can find more information at API reference webpages - Context, Token. But the best way of understanding the behavior is reading through the generated ANTLR classes such as <GrammarName>Parser etc. And to be complete, I attach a link to the book.

should it be allowed to change the method signature in a non statically typed language

Hypothetic and academic question.
pseudo-code:
<pre><code>
class Book{
read(theReader)
}
class BookWithMemory extends Book {
read(theReader, aTimestamp = null)
}
</pre></code>
Assuming:
an interface (if supported) would prohibit it
default value for parameters are supported
Notes:
PHP triggers an strict standards error for this.
I'm not surprised that PHP strict mode complains about such an override. It's very easy for a similar situation to arise unintentionally in which part of a class hierarchy was edited to use a new signature and a one or a few classes have fallen out of sync.
To avoid the ambiguity, name the new method something different (for this example, maybe readAt?), and override read to call readAt in the new class. This makes the intent plain to the interpreter as well as anyone reading the code.
The actual behavior in such a case is language-dependent -- more specifically, it depends on how much of the signature makes up the method selector, and how parameters are passed.
If the name alone is the selector (as in PHP or Perl), then it's down to how the language handles mismatched method parameter lists. If default arguments are processed at the call site based on the static type of the receiver instead of at the callee's entry point, when called through a base class reference you'd end up with an undefined argument value instead of your specified default, similarly to what would happen if there was no default specified.
If the number of parameters (with or without their types) are part of the method selector (as in Erlang or E), as is common in dynamic languages that run on JVM or CLR, you have two different methods. Create a new overload taking additional arguments, and override the base method with one that calls the new overload with default argument values.
If I am reading the question correctly, this question seems very language specific (as in it is not applicable to all dynamic languages), as I know you can do this in ruby.
class Book
def read(book)
puts book
end
end
class BookWithMemory < Book
def read(book,aTimeStamp = nil)
super book
puts aTimeStamp
end
end
I am not sure about dynamic languages besides ruby. This seems like a pretty subjective question as well, as at least two languages were designed on either side of the issue (method overloading vs not: ruby vs php).

Resources