Bug 182786 - Wrong MethodDeclaration in AST tree
Summary: Wrong MethodDeclaration in AST tree
Status: VERIFIED INVALID
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2.1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.3 M7   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-04-17 12:49 EDT by Steven Decock CLA
Modified: 2007-05-03 20:55 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Steven Decock CLA 2007-04-17 12:49:03 EDT
When trying to parse a java source file (.java) using JDT and the abstract syntax tree (AST), I stumbled on this issue:

In certain cases commented text is wrongly considered as a method declaration.
This happens in cases where the comment (or javadoc) contains parentheses. The following piece of code illustrates this problem:

////////////////////////////////////////////////////
package com.me.test;

public class KAdresse {

    /**
     * This is not a method, really, I'm telling you: notAMethod (one, two, ...)
     */
    private String tAdresOngebSit;

    /**
     * Gemeentenaam.
     * Zit normaal in KCodeNisCommune, dit veld dient voor de bestaande gevallen waar in de migratie de link naar de gemeentetabel niet kan gelegd worden.
     *  Dit veld bevat dan de huidige gemeentenaam.
     * [JFC] conserver la meme regle. Attention, la migration devrait ne plus permettre d'anciens noms de communes ou des noms non valides. Ici sert à la migration mais non utilisé pour la recherche.
     */
    private String tAdresNisComNom;

    /**
     * Référence vers la tables des codes de rue
     * @clientCardinality 0..*
     * @supplierCardinality 1
     * @label référence à
     */
    private KCodeRue lnkKCodeRue;

    /**
     * Référence vers la table des codes NIS de commune
     * @clientCardinality 0..*
     * @supplierCardinality 0..1
     * @label référence à
     */
    private KCodeNisCommune lnkKCodeNisCommune;
}
////////////////////////////////////////////////////

In the first line of comment the following text gets mistaken for a method: "notAMethod (one, two, ...)"

When parsing this code a MethodDeclaration object is created with the name "notAMethod", although this is clearly not a method, but part of the comment of the field tAdresOngebSit.

This is the code used to parse the source file:

////////////////////////////////////////////////////
package uml2java;

import java.io.*;
import java.util.Iterator;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.dom.*;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jface.text.*;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;

public class Analyzer {

	protected static CompilationUnit parse(char[] unit) {
		ASTParser parser = ASTParser.newParser(AST.JLS3); 
		parser.setKind(ASTParser.K_COMPILATION_UNIT);
		parser.setSource(unit); // set source
		parser.setResolveBindings(true); // we need bindings later on
		return (CompilationUnit) parser.createAST(null); // parse
	}
	
	public static String readTextFile(String fullPathFilename) throws IOException {
		StringBuffer sb = new StringBuffer(1024);
		BufferedReader reader = new BufferedReader(new FileReader(fullPathFilename));
				
		char[] chars = new char[1024];
		int numRead = 0;
		while( (numRead = reader.read(chars)) > -1){
			sb.append(String.valueOf(chars));	
		}

		reader.close();

		return sb.toString();
	}


	public static void main(String[] args) throws FileNotFoundException {
		try {
			MethodDeclaration methodToChange = null;
			String fileContent = readTextFile("D:\\input.java"); 
			Document doc = new Document(fileContent);
			char[] charContent = fileContent.toCharArray();
			CompilationUnit cu = parse(charContent);
			TypeDeclaration type = null;
			for (Iterator iter = cu.types().iterator(); iter.hasNext();) {
				type = (TypeDeclaration) iter.next();
				for (Iterator iterator = type.bodyDeclarations().iterator(); iterator
						.hasNext();) {
					BodyDeclaration bodyDecl = (BodyDeclaration) iterator.next();
					if (bodyDecl.getNodeType() == ASTNode.METHOD_DECLARATION) {
						MethodDeclaration methodDecl = (MethodDeclaration) bodyDecl;
						System.out.print(methodDecl.getName().getFullyQualifiedName()
					}
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedTreeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadLocationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
}
////////////////////////////////////////////////////

The above code parses an input file (d:\input.java) and loops through all method declarations and writes the method names to the console. Although the source for KAdresse (see above) does not contain any methods, the name "notAMethod " is written to the console.

The occurrence of this problem is very erratic, as minor changes to the input file give different results. If for example the javadoc comment for the tAdresNisComNom field is removed, the problem does no longer occur, even though the text "notAMethod (one, two, ...)" is still there.
Comment 1 Olivier Thomann CLA 2007-04-26 22:37:51 EDT
With your code, the file is not completely read.
If you change the for loop with:
		while ((numRead = reader.read(chars)) > -1) {
			sb.append(chars, 0, numRead);
		}
it should work better.

Another point, resolveBindings(true) doesn't work if you don't set a java project.
This is explained in the javadoc of the ASTParser class.
Closing as INVALID.
Comment 2 Olivier Thomann CLA 2007-04-26 23:27:54 EDT
Reopening for further investigation. Even if the source is incorrect, it looks boggus to try to retrieve method header inside comments.
Comment 3 Olivier Thomann CLA 2007-04-30 12:13:40 EDT
With your way to read the source you actually end up with this source:
package com.me.test;

public class KAdresse {

    /**
     * This is not a method, really, I'm telling you: notAMethod (one, two,
...)
     */
    private String tAdresOngebSit;

    /**
     * Gemeentenaam.
     * Zit normaal in KCodeNisCommune, dit veld dient voor de bestaande
gevallen waar in de migratie de link naar de gemeentetabel niet kan gelegd
worden.
     *  Dit veld bevat dan de huidige gemeentenaam.
     * [JFC] conserver la meme regle. Attention, la migration devrait ne plus
permettre d'anciens noms de communes ou des noms non valides. Ici sert à la
migration mais non utilisé pour la recherche.
     */
    private String tAdresNisComNom;

    /**
     * Référence vers la tables des codes de rue
     * @clientCardinality 0..*
     * @supplierCardinality 1
     * @label référence à
     */
    private KCodeRue lnkKCodeRue;

    /**
     * Référence vers la table des codes NIS de commune
     * @clientCardinality 0..*
     * @supplierCardinality 0..1
     * @label référence à
     */
    private KCodeNisCommune lnkKCodeNisCommune;
}is not a method, really, I'm telling you: notAMethod (one, two,
...)
     */
    private String tAdresOngebSit;

    /**
     * Gemeentenaam.
     * Zit normaal in KCodeNisCommune, dit veld dient voor de bestaande
gevallen waar in de migratie de link naar de gemeentetabel niet kan gelegd
worden.
     *  Dit veld bevat dan de huidige gemeentenaam.
     * [JFC] conserver la meme regle. Attention, la migration devrait ne plus
permettre d'anciens noms de communes ou des noms non valides. Ici sert à la
migration mais non utilisé pour la recherche.
     */
    private String tAdresNisComNom;

    /**
     * Référence vers la tables des codes de rue
     * @clientCardinality 0..*
     * @supplierCardinality 1
     * @label référence à
     */
    private KCodeRue lnkKCodeRue;

    /**
     * Référence vers la table des codes NIS de commune
     * @clientCardinality 0..*
     * @supplierCardinality 0..1
     * @label 

And if you look at the code below the field lnkKCodeNisCommune, you can see that you also have notAMethod. This is where the method is coming from at the end.

    private KCodeNisCommune lnkKCodeNisCommune;
}is not a method, really, I'm telling you: notAMethod (one, two,
...)

So I won't make any changes for this. The recovery mechanism is not looking inside comments, but the given code is so busted, that the compiler tries to infer malformed methods and fields out of the given source.
Closing as INVALID.
If you believe we are wrong, please reopen and explain what you expect.
Comment 4 Olivier Thomann CLA 2007-05-03 20:55:46 EDT
Verify for 3.3M7 with I20070503-1400.