How to use ASTRewrite for inserting/updating body of the method using JDT? - eclipse-plugin

I want to write code inside the method using JDT's ASTRewrite. I tried using ASTRewrite but its not working. Kindly help. Sample code of my ASTRewrite is below:
public void implementMethod(MethodDeclaration methodToBeImplemented) {
astOfMethod = methodToBeImplemented.getAST();
ASTRewrite astRewrite = ASTRewrite.create(astOfMethod);
Block body = astOfMethod.newBlock();
methodToBeImplemented.setBody(body);
MethodInvocation newMethodInvocation = astOfMethod.newMethodInvocation();
QualifiedName name = astOfMethod.newQualifiedName(astOfMethod
.newSimpleName("System"), astOfMethod.newSimpleName("out"));
newMethodInvocation.setExpression(name);
newMethodInvocation.setName(astOfMethod.newSimpleName("println"));
ExpressionStatement expressionStatement = astOfMethod.newExpressionStatement(newMethodInvocation);
body.statements().add(expressionStatement);
astRewrite.set(oldBody, MethodDeclaration.BODY_PROPERTY, body, null);
ctcObj.document = new Document(ctcObj.source);
edit = astRewrite.rewriteAST(ctcObj.document, null);
try {
edit.apply(ctcObj.document);
} catch (MalformedTreeException e) {
e.printStackTrace();
} catch (BadLocationException e) {
e.printStackTrace();
}
}
I tried using different types of ASTRewrite.set() but it generates either compile time error saying illegal parameters or run time exceptions.

You need one more step: Write to file. edit(apply) does not write to file.
Example see:
Rewrite method incorrectly rewrite change to ICompilationUnit the second rewrite update

(As the declaration of oldBody is missing I'm assuming in the following a correct declaration.)
The following line must be removed:
methodToBeImplemented.setBody(body);
With the above line you manually changing a node which should be a target of ASTRewrite. Usually that is not recommended.
Next, your call
astRewrite.set(oldBody, MethodDeclaration.BODY_PROPERTY, body, null);
fails because the target node (1st parameter) and target node property (2nd parameter) must be matching regarding the node class. But in your case it is Block (oldBody) and MethodDeclaration (BODY_PROPERTY). A proper call is:
astRewrite.set(methodToBeImplemented, MethodDeclaration.BODY_PROPERTY, body, null);
An alternative solution to ASTRewrite.set() would be this call:
astRewrite.replace(oldBody, body, null);

Related

How to use an existing ArrayList inside Lambda Expression/block?

I am new to Java 8 and was trying to rewrite an existing code snippet logic using the Java 8 features.
However I am not sure how to use an existing arrayList defined outside the block to get values from it when it is placed inside the lambda block. It complains that it has to be final or effectively final.
I started with converting the inner traditional for loop and encountered the same issues with a counter variable which I was able to sort using AtomicInteger but am not sure how to do that for arrayList as well as I cannot also define the arrayList inside the lambda block since it has a dependency of an i variable that is present in the outer while loop.
Any help will be much appreciated !!! Thanks in advance.
Below is my code snippet :-
public String somemethod(ArrayList someValues){
int i=0;
String status="Failed";
ArrayList someOtherValues = new ArrayList();
try
{
while ( i < (someValues.size()))
{
someOtherValues = (ArrayList) someValues.get(i);
someOtherValues.replaceAll(t -> Objects.isNull(t) ? "" : t); //converting every null to "" within the arrayList someOtherValues
int count=4;
AtomicInteger counter=new AtomicInteger(5);
if(!someOtherValues.get(0).toString().equals(""))
{
while ( count < (someOtherValues.size()))
{
IntStream.range(0, 3).forEach(k -> {
someObjectClass someObject=new someObjectClass();
someOtherObjectClass id = new someOtherObjectClass(someOtherValues.get(0).toString(),someOtherValues.get(count).toString()) //Line where the error is
someObject=new someObjectClass(id);
someObject.setId(id);
if(someCondition)
{
try
{
someObject.setSomething(someValue);
counter.incrementAndGet()
}
}
someObject.setsomeOtherValues1(someOtherValues.get(1).toString());
someObject.setsomeOtherValues2(someOtherValues.get(3).toString())
}
count=counter.get();
counter.incrementAndGet();
}
}
i++;
}
catch(Exception e)
{
return status;
}
}
Right now where it is pending is it complains that someOtherValues, which is an existing arrayList defined outside the lambda block needs to be final or effectively final in order to fetch elements.
Is it literally not possible to change/optimize the above function into a fewer lines of code using Java 8 streams/lambdas/forEach ?
As a general rule it is not a good idea to try and change outside variables inside a lambda definition. But since Java's very loose concept of final fields and variables only applies to assigning values, it can still be done.
The only thing you cannot do in a lambda expression with variable defined outside is assigning new values.
So this does not compile:
List<String> lst = new ArrayList<>();
myLambda = e -> {
lst = new ArrayList<>(); //this violates the 'final' rule
lst.add(e);
}
It is however possible to call any method of the outside variable, even if it changes the state of the variable. This will work:
myLambda = e -> {
lst.add(e);
}
Even though you're still changed the state of the variable lst, this is legal code.
But I strongly advise against it. Lambdas are meant to used in a functional matter and should not change any variables defined elsewhere. It's a better choice to create a list inside the lambda, return it from the lambda and then add it to the outside list.

how to catch minor errors?

I have a little ANTLR v4 grammer and I am implementing a visitor on it.
Lets say it is a simple calculator and every input must be terminated with a ";"
e.g. x=4+5;
If I do not put the ; at the end, then it is working too but I get a output the teminal.
line 1:56 missing ';' at '<EOF>'
Seems it can find the rule and more or less ignores the missing terminal ";".
I would prefer a strict error or an exception instead of this soft information.
The output is generated by the line
ParseTree tree = parser.input ()
Is there a way I can intensify the error-handling and check for that kind of error?
Yes, you can. Like you, I wanted a 100% perfect parse from user-submitted text and so created a strict error handler that prevents recovery from even simple errors.
The first step is in removing the default error listeners and adding your own STRICT error handler:
AntlrInputStream inputStream = new AntlrInputStream(stream);
BailLexer lexer = new BailLexer(inputStream); // TALK ABOUT THIS AT BOTTOM
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
LISBASICParser parser = new LISBASICParser(tokenStream);
parser.RemoveErrorListeners(); // UNHOOK ERROR HANDLER
parser.ErrorHandler = new StrictErrorStrategy(); // REPLACE WITH YOUR OWN
LISBASICParser.CalculationContext context = parser.calculation();
CalculationVisitor visitor = new CalculationVisitor();
visitor.VisitCalculation(context);
Here's my StrictErrorStrategy class. It inherits from the DefaultErrorStrategy class and overrides the two 'recovery' methods that are letting small errors like your semicolon error be recoverable:
public class StrictErrorStrategy : DefaultErrorStrategy
{
public override void Recover(Parser recognizer, RecognitionException e)
{
IToken token = recognizer.CurrentToken;
string message = string.Format("parse error at line {0}, position {1} right before {2} ", token.Line, token.Column, GetTokenErrorDisplay(token));
throw new Exception(message, e);
}
public override IToken RecoverInline(Parser recognizer)
{
IToken token = recognizer.CurrentToken;
string message = string.Format("parse error at line {0}, position {1} right before {2} ", token.Line, token.Column, GetTokenErrorDisplay(token));
throw new Exception(message, new InputMismatchException(recognizer));
}
public override void Sync(Parser recognizer) { }
}
Overriding these two methods allows you to stop (in this case with an exception that is caught elsewhere) on ANY parser error. And making the Sync method empty prevents the normal 're-sync after error' behavior from happening.
The final step is in catching all LEXER errors. You do this by creating a new class that inherits from your main lexer class; it overrides the Recover() method like so:
public class BailLexer : LISBASICLexer
{
public BailLexer(ICharStream input) : base(input) { }
public override void Recover(LexerNoViableAltException e)
{
string message = string.Format("lex error after token {0} at position {1}", _lasttoken.Text, e.StartIndex);
BasicEnvironment.SyntaxError = message;
BasicEnvironment.ErrorStartIndex = e.StartIndex;
throw new ParseCanceledException(BasicEnvironment.SyntaxError);
}
}
(Edit: In this code, BasicEnvironment is a high-level context object I used in the application to hold settings, errors, results, etc. So if you decide to use this, either do as another reader commented below, or substitute your own context/container.)
With this in place, even small errors during the lexing step will be caught as well. With these two overridden classes in place, the user of my app must supply absolutely perfect syntax to get a successful execution. There you go!
Because my ANTLR is in Java I add the answer here too. But it is the same idea as the accepted answer.
TempParser parser = new TempParser (tokens);
parser.removeErrorListeners ();
parser.addErrorListener (new BaseErrorListener ()
{
#Override
public void syntaxError (final Recognizer <?,?> recognizer, Object sym, int line, int pos, String msg, RecognitionException e)
{
throw new AssertionError ("ANTLR - syntax-error - line: " + line + ", position: " + pos + ", message: " + msg);
}
});

Writing Custom Rule for Android-Lint

Q (tldr;): How do I use the JavaScanner in android-lint to check if a particular function call with a specific string as a parameter has been surrounded by a try/catch block.
Details: I have completed the android-lint tutorials on the official site and have gone through the source of the existing lint-checks. However, I can't seem to grasp the workflow for this AST-based parsing of JavaScanner. What I'm trying to achieve is to catch a function that sets a specific property and surround it with a try/catch block. For example:
MyPropertySettings.set("SOME_PROPERTY", "SOME_VAL");
should not trigger the lint rule but:
MyPropertySettings.set("SOME_SENSITIVE_PROPERTY", "SOME_VAL");
should because it's not surrounded by a try/catch block with SetPropertyException. I don't want to introduce the try/catch to the function itself because it only throws the exception in extremely rare cases (and the internals of the function are based on some reflection mojo).
For this question, even a workflow/hint would be fine. If I can get the first few steps, I might be able to grasp it better.
Update:
After some more study, I have found that I need to set the set function above in getApplicableMethodNames() and then, somehow read the property of that function to decide if the check applies. That part should be easy.
Surrounding try/catch would be more difficult and I gather I would need to do some "flow analysis". How is the question now.
Well, along with the getApplicableMethodNames() method, you need to override the visitMethod() function. You will get the MethodInvocationNode. Just fetch the arguments passed in the invocation using the node.astArguments() function. This returns a list of arguments that you can iterate through using a StrictListAccessor. Check the arguments passed and if it matches your criterion, run a loop and keep calculating the parent node of the invocation node till a try node is found. If it is a try node, then you can get a list of catches using node.astCatches(). Scan the list and find the appropriate exception. If not found, then report.
You can code like this:
check if it is surrounded by try/catch:
#Override
public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) {
// check the specified class that invoke the method
JavaParser.ResolvedMethod method = (JavaParser.ResolvedMethod) context.resolve(node);
JavaParser.ResolvedClass clzz = method.getContainingClass();
boolean isSubClass = false;
// sSupportSuperType = {"class name"};
for (int i = 0; i < sSupportSuperType.length; i++) {
if (clzz.isSubclassOf(sSupportSuperType[i], false)) {
isSubClass = true;
break;
}
}
if (!isSubClass) return;
// check if surrounded by try/catch
Node parent = node;
while (true) {
Try tryCatch = context.getParentOfType(parent, Try.class);
if (tryCatch == null) {
break;
} else {
for (Catch aCatch : tryCatch.astCatches()) {
TypeReference catchType = aCatch.astExceptionDeclaration().astTypeReference();
}
parent = tryCatch;
}
}
// get the arguments string
String str = node.astArguments().first().toString();
if (!str.startsWith("\"SOME_PROPERTY\"")) {
context.report(ISSUE, node, context.getLocation(node), "message");
}
}
before this you have to define the specific method by override:
#Override
public List<String> getApplicableMethodNames() {
return Collections.singletonList("set");
}

How do I express a void method call as the result of DynamicMetaObject.BindInvokeMember?

I'm trying to give a short example of IDynamicMetaObjectProvider for the second edition of C# in Depth, and I'm running into issues.
I want to be able to express a void call, and I'm failing. I'm sure it's possible, because if I dynamically call a void method using the reflection binder, all is fine. Here's a short but complete example:
using System;
using System.Dynamic;
using System.Linq.Expressions;
class DynamicDemo : IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression expression)
{
return new MetaDemo(expression, this);
}
public void TestMethod(string name)
{
Console.WriteLine(name);
}
}
class MetaDemo : DynamicMetaObject
{
internal MetaDemo(Expression expression, DynamicDemo demo)
: base(expression, BindingRestrictions.Empty, demo)
{
}
public override DynamicMetaObject BindInvokeMember
(InvokeMemberBinder binder, DynamicMetaObject[] args)
{
Expression self = this.Expression;
Expression target = Expression.Call
(Expression.Convert(self, typeof(DynamicDemo)),
typeof(DynamicDemo).GetMethod("TestMethod"),
Expression.Constant(binder.Name));
var restrictions = BindingRestrictions.GetTypeRestriction
(self, typeof(DynamicDemo));
return new DynamicMetaObject(target, restrictions);
}
}
class Test
{
public void Foo()
{
}
static void Main()
{
dynamic x = new Test();
x.Foo(); // Works fine!
x = new DynamicDemo();
x.Foo(); // Throws
}
}
This throws an exception:
Unhandled Exception:
System.InvalidCastException: The
result type 'System.Void' of the
dynamic binding produced by the object
with type 'DynamicDemo' for the binder
'Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder'
is not compatible with the result type 'System.Object' expected by the
call site.
If I change the method to return object and return null, it works fine... but I don't want the result to be null, I want it to be void. That works fine for the reflection binder (see the first call in Main) but it fails for my dynamic object. I want it to work like the reflection binder - it's fine to call the method, so long as you don't try to use the result.
Have I missed a particular kind of expression I can use as the target?
This is similar to:
DLR return type
You do need to match the return type specified by the ReturnType property. For all of the standard binaries this is fixed to object for almost everything or void (for the deletion operations). If you know you're making a void call I'd suggest wrapping it in:
Expression.Block(
call,
Expression.Default(typeof(object))
);
The DLR used to be quite lax about what it would allow and it would provide some minimal amount of coercion automatically. We got rid of that because we didn't want to provide a set of convensions which may or may not have made sense for each language.
It sounds like you want to prevent:
dynamic x = obj.SomeMember();
There's no way to do that, there'll always be a value returned that the user can attempt to continue to interact with dynamically.
I don't like this, but it seems to work; the real problem seems to be the binder.ReturnType coming in oddly (and not being dropped ("pop") automatically), but:
if (target.Type != binder.ReturnType) {
if (target.Type == typeof(void)) {
target = Expression.Block(target, Expression.Default(binder.ReturnType));
} else if (binder.ReturnType == typeof(void)) {
target = Expression.Block(target, Expression.Empty());
} else {
target = Expression.Convert(target, binder.ReturnType);
}
}
return new DynamicMetaObject(target, restrictions);
Perhaps the callsite expects null to be returned but discards the result - This enum looks interesting, particularly the "ResultDiscarded" flag...
[Flags, EditorBrowsable(EditorBrowsableState.Never)]
public enum CSharpBinderFlags
{
BinaryOperationLogical = 8,
CheckedContext = 1,
ConvertArrayIndex = 0x20,
ConvertExplicit = 0x10,
InvokeSimpleName = 2,
InvokeSpecialName = 4,
None = 0,
ResultDiscarded = 0x100,
ResultIndexed = 0x40,
ValueFromCompoundAssignment = 0x80
}
Food for thought...
UPDATE:
More hints can be gleaned from Microsoft / CSharp / RuntimeBinder / DynamicMetaObjectProviderDebugView which is used (I presume) as a visualizer for debuggers. The method TryEvalMethodVarArgs examines the delegate and creates a binder with the result discarded flag (???)
Type delegateType = Expression.GetDelegateType(list.ToArray());
if (string.IsNullOrEmpty(name))
{
binder = new CSharpInvokeBinder(CSharpCallFlags.ResultDiscarded, AccessibilityContext, list2.ToArray());
}
else
{
binder = new CSharpInvokeMemberBinder(CSharpCallFlags.ResultDiscarded, name, AccessibilityContext, types, list2.ToArray());
}
CallSite site = CallSite.Create(delegateType, binder);
... I'm at the end of my Reflector-foo here, but the framing of this code seems a bit odd since the TryEvalMethodVarArgs method itself expects an object as a return type, and the final line returns the result of the dynamic invoke. I'm probably barking up the wrong [expression] tree.
-Oisin
The C# binder (in Microsoft.CSharp.dll) knows whether or not the result is used; as x0n (+1) says, it keeps track of it in a flag. Unfortunately, the flag is buried inside a CSharpInvokeMemberBinder instance, which is a private type.
It looks like the C# binding mechanism uses ICSharpInvokeOrInvokeMemberBinder.ResultDiscarded (a property on an internal interface) to read it out; CSharpInvokeMemberBinder implements the interface (and property). The job appears to be done in Microsoft.CSharp.RuntimeBinder.BinderHelper.ConvertResult(). That method has code that throws if the aforementioned ResultDiscarded property doesn't return true if the type of the expression is void.
So it doesn't look to me like there's an easy way to tease out the fact that the result of the expression is dropped from the C# binder, in Beta 2 at least.

Force antlr3 to immediately exit when a rule fails

I've got a rule like this:
declaration returns [RuntimeObject obj]:
DECLARE label value { $obj = new RuntimeObject($label.text, $value.text); };
Unfortunately, it throws an exception in the RuntimeObject constructor because $label.text is null. Examining the debug output and some other things reveals that the match against "label" actually failed, but the Antlr runtime "helpfully" continues with the match for the purpose of giving a more helpful error message (http://www.antlr.org/blog/antlr3/error.handling.tml).
Okay, I can see how this would be useful for some situations, but how can I tell Antlr to stop doing that? The defaultErrorHandler=false option from v2 seems to be gone.
I don't know much about Antlr, so this may be way off base, but the section entitled "Error Handling" on this migration page looks helpful.
It suggests you can either use #rulecatch { } to disable error handling entirely, or override the mismatch() method of the BaseRecogniser with your own implementation that doesn't attempt to recover. From your problem description, the example on that page seems like it does exactly what you want.
You could also override the reportError(RecognitionException) method, to make it rethrow the exception instead of print it, like so:
#parser::members {
#Override
public void reportError(RecognitionException e) {
throw new RuntimeException(e);
}
}
However, I'm not sure you want this (or the solution by ire_and_curses), because you will only get one error per parse attempt, which you can then fix, just to find the next error. If you try to recover (ANTLR does it okay) you can get multiple errors in one try, and fix all of them.
You need to override the mismatch and recoverFromMismatchedSet methods to ensure an exception is thrown immediately (examples are for Java):
#members {
protected void mismatch(IntStream input, int ttype, BitSet follow) throws RecognitionException {
throw new MismatchedTokenException(ttype, input);
}
public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException {
throw e;
}
}
then you need to change how the parser deals with those exceptions so they're not swallowed:
#rulecatch {
catch (RecognitionException e) {
throw e;
}
}
(The bodies of all the rule-matching methods in your parser will be enclosed in try blocks, with this as the catch block.)
For comparison, the default implementation of recoverFromMismatchedSet inherited from BaseRecognizer:
public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException {
if (mismatchIsMissingToken(input, follow)) {
reportError(e);
return getMissingSymbol(input, e, Token.INVALID_TOKEN_TYPE, follow);
}
throw e;
}
and the default rulecatch:
catch (RecognitionException re) {
reportError(re);
recover(input,re);
}