Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with creating matcher. #2982

Closed
MakroCZ opened this issue May 22, 2019 · 10 comments
Closed

Problem with creating matcher. #2982

MakroCZ opened this issue May 22, 2019 · 10 comments
Labels

Comments

@MakroCZ
Copy link

MakroCZ commented May 22, 2019

Hello,
I'm trying to implement template matcher (patterns give me some internal missing CtElement for to provide Factory error).
My matcher class is from website:

public class NullCheckMatcher {
    
    public TemplateParameter<Collection<?>> _col_;
    
    public void matcher1() {
    if (_col_.S().size() > 10) {
      throw new IndexOutOfBoundsException();
    }
  }
}

I'm trying to create matcher in processor:

Factory f = e.getFactory();
CtClass<?> klass = f.Class().get(NullCheckMatcher.class);
CtMethod m = (CtMethod) klass.filterChildren(new NameFilter("matcher1")).first();
CtBlock block = m.getBody();

CtIf templateRoot = (CtIf) ((CtMethod) klass.getElements(new NameFilter("matcher1")).get(0)).getBody().getStatement(0);

variable e is CtMethod.
Problem is that body of method (variable block) contains no statements, so the last statement gives me IndexOutOfBoundException: 0.
Thanks for help.

@monperrus
Copy link
Collaborator

Thanks for the bug report. It should work. Could you make a pull-request with a failing test case?

@nharrand nharrand added the bug label Jun 5, 2019
@Egor18
Copy link
Contributor

Egor18 commented Jun 11, 2019

I tried to reproduce the problem, but this works fine:

public void testStatementsBug() {
	Launcher launcher = new Launcher();
	launcher.addInputResource("./src/test/java/spoon/test/ctBlock/testclasses/NullCheckMatcher.java");
	launcher.buildModel();

	Factory f = launcher.getFactory();
	CtClass<?> klass = f.Class().get(NullCheckMatcher.class);
	CtMethod m = (CtMethod) klass.filterChildren(new NameFilter("matcher1")).first();
	CtBlock block = m.getBody();

	CtIf templateRoot = (CtIf) ((CtMethod) klass.getElements(new NameFilter("matcher1")).get(0)).getBody().getStatement(0);

	System.out.println(templateRoot);
}

output:

if ((_col_.S().size()) > 10) {
    throw new java.lang.IndexOutOfBoundsException();
}

@MakroCZ, maybe you forgot to build the model or add NullCheckMatcher.java as an input resource?
You would get IndexOutOfBoundException in this case.
Could you please show your full code?

@MakroCZ
Copy link
Author

MakroCZ commented Jun 12, 2019

Sorry for my inactivity. I didn't have access to PC and have exams.
I was just using it from running process but didn't load it before, because I missunderstand the code. I thought that it will load that specified class and analyze it...
So I need to create new Launcher inside the processor to load and build model for that matcher? (I don't want to load it globally)
I was debugging the code by separating it into parts and found, that I get empty body from method.
I think it should be nice to get some error, that requested class is not loaded, not returning class with that name containing method with requested name but with empty body. It really confused me.

@Egor18
Copy link
Contributor

Egor18 commented Jun 13, 2019

@MakroCZ, you don't need to create a new Launcher inside your processor, but you still have to pass input sources with -i:
$ java -classpath /path/to/binary/of/your/processor.jar:spoon-core-7.5.0-beta-21-jar-with-dependencies.jar spoon.Launcher -i /path/to/src/of/your/project -p processors.YourProcessor

See the example here: http://spoon.gforge.inria.fr/first_analysis_processor.html

Alternatively, you can create Launcher from code and use addInputResources and addProcessor, insead of cli interface.

Can you show how you run your processor?

@MakroCZ
Copy link
Author

MakroCZ commented Jun 14, 2019

I am launching it from java SwingWorker (code below)

@Override
protected Void doInBackground() throws Exception {
    for (int i = 0; i < files.size(); i++) {
        Launcher l = new Launcher();
        l.addInputResource(files.get(i).getPath());
        for (MyAbstractProcessor t : processors) {
            l.addProcessor(t);
        }
        publish(i+1);
        l.run();
    }
    return null;
}

@Egor18 As you mentioned to add it as input. I don't want it to be global, it's why I asked about creating new Launcher in processor to build the matcher model.

@Egor18
Copy link
Contributor

Egor18 commented Jun 15, 2019

@MakroCZ, I don't quite get the idea of creating a new Launcher in the processor. The launcher runs processors over the input sources.
By the way, why are you creating a new Launcher for each file?

Does the exception still occur?

@MakroCZ
Copy link
Author

MakroCZ commented Jun 16, 2019

I am creating new Launcher for each file because it was the only way I was able to find to have some progress measurement (I am showing index of actually processed file).

I don't want to add all matchers to all processors (input resource in SwingWorker) because of globality (I don't know it but I think that with many processors and many different matchers used globally, whole model will be pretty big and can cause performance problems - navigating throught the AST) so I want matchers to be local, only for processor which needs them. And because of this I am asking if I have to create new Launcher in processor which will build AST from matcher class.
I hope it is understandable.

I am actually not able to test if exception still occurs but I will test it as soon as possible.

@MakroCZ
Copy link
Author

MakroCZ commented Jul 10, 2019

After finishing my exams and returning from vacation I tested creating launcher in processor, add matcher class to launcher, build model from it and it looks working.

But I think that there is one bad understable documentation (at least for me) or maybe bug?:
ClassFactory.get() should return found class or null.
I thought that it will load java src file and return model but it doesn't.
Based on this thread I think that it looks into AST provided by factory (CtElement.getFactory()).
But there is one think I don't understand (if things above are true) is:

  1. Requested class was not loaded into AST
  2. ClassFactory.get() returns requested class with requested method but everything was empty (no statements in method body)
    I think that it should return null (class not loaded into AST), not empty class because it really confused me and I was looking for solution on bad places.

@monperrus
Copy link
Collaborator

get(String) returns null if the class is not in the source classpath (even if it is in the binary classpath).

get(Class) returns null if the class is neither in the source classpath nor in the binary classpath, and returns a shadow class if it is only in the binary classpath. Note that a shadow class has an empty method body, if you need a shadow class with method body, see spoon-decompiler)

@monperrus
Copy link
Collaborator

Closing this issue. Don't hesitate to create a new issue of you have a new problem that is not related to matchers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants