/*******************************************************************************
 * Copyright (c) 2004, 2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IBM - Initial API and implementation
 *    Markus Schorn (Wind River Systems)
 *    Anton Leherbauer (Wind River Systems)
 *******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;

import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression;
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTPointer;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorObjectStyleMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorUndefStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.internal.core.parser.ParserException;

public class DOMLocationMacroTests extends AST2BaseTest {

	final ParserLanguage[] languages = new ParserLanguage[] { ParserLanguage.C, ParserLanguage.CPP };
	
    public DOMLocationMacroTests() {
	}

	public DOMLocationMacroTests(String name) {
		super(name);
	}

	public void testObjectStyleMacroExpansionSimpleDeclarator() throws Exception
    {
        StringBuffer buffer = new StringBuffer( "#define ABC D\n" ); //$NON-NLS-1$
        buffer.append( "int ABC;"); //$NON-NLS-1$
        String code = buffer.toString();
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            IASTPreprocessorObjectStyleMacroDefinition ABC = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[0];
            IASTSimpleDeclaration var = (IASTSimpleDeclaration) tu.getDeclarations()[0];
            IASTDeclarator d = var.getDeclarators()[0];
            assertEquals( d.getName().toString(), "D"); //$NON-NLS-1$
            IASTNodeLocation [] declaratorLocations = d.getNodeLocations();
            assertEquals( declaratorLocations.length, 1 );
            IASTMacroExpansionLocation expansion = (IASTMacroExpansionLocation) declaratorLocations[0];
            IASTPreprocessorObjectStyleMacroDefinition fromExpansion = (IASTPreprocessorObjectStyleMacroDefinition) expansion.getExpansion().getMacroDefinition();
            assertEqualsMacros( fromExpansion, ABC );
            assertEquals( expansion.getNodeOffset(), 0 );
            assertEquals( expansion.getNodeLength(), 1 );
            IASTNodeLocation [] macroLocation = expansion.getExpansion().getNodeLocations();
            assertEquals( macroLocation.length, 1 );
            assertTrue( macroLocation[0] instanceof IASTFileLocation );
            assertEquals( macroLocation[0].getNodeOffset(), code.indexOf( "int ABC;") + "int ".length() ); //$NON-NLS-1$ //$NON-NLS-2$
            assertEquals( macroLocation[0].getNodeLength(), "ABC".length() ); //$NON-NLS-1$
        }
    }
    
    public void testObjectMacroExpansionModestDeclarator() throws Exception
    {
        StringBuffer buffer = new StringBuffer( "#define ABC * D\n" ); //$NON-NLS-1$
        buffer.append( "int ABC;"); //$NON-NLS-1$
        String code = buffer.toString();
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            IASTPreprocessorObjectStyleMacroDefinition ABC = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[0];
            IASTSimpleDeclaration var = (IASTSimpleDeclaration) tu.getDeclarations()[0];
            IASTDeclarator d = var.getDeclarators()[0];
            assertEquals( d.getName().toString(), "D"); //$NON-NLS-1$
            assertEquals( d.getPointerOperators().length, 1 );
            IASTNodeLocation [] declaratorLocations = d.getNodeLocations();
            assertEquals( declaratorLocations.length, 1 );
            IASTMacroExpansionLocation expansion = (IASTMacroExpansionLocation) declaratorLocations[0];
            IASTPreprocessorObjectStyleMacroDefinition fromExpansion = (IASTPreprocessorObjectStyleMacroDefinition) expansion.getExpansion().getMacroDefinition();
            assertEqualsMacros( fromExpansion, ABC );
            assertEquals( expansion.getNodeOffset(), 0 );
            assertEquals( 2, expansion.getNodeLength() );
            IASTNodeLocation [] macroLocation = expansion.getExpansion().getNodeLocations();
            assertEquals( macroLocation.length, 1 );
            assertTrue( macroLocation[0] instanceof IASTFileLocation );
            assertEquals( macroLocation[0].getNodeOffset(), code.indexOf( "int ABC;") + "int ".length() ); //$NON-NLS-1$ //$NON-NLS-2$
            assertEquals( macroLocation[0].getNodeLength(), "ABC".length() ); //$NON-NLS-1$
            
            IASTName n = d.getName();
            IASTNodeLocation [] nameLocations = n.getNodeLocations();
            assertEquals( nameLocations.length, 1 );
            final IASTMacroExpansionLocation nodeLocation = (IASTMacroExpansionLocation) nameLocations[0];
            assertEquals( nodeLocation.getNodeOffset(), 1 );
            assertEquals( nodeLocation.getNodeLength(), 1 );
            
            assertEquals( nodeLocation.getExpansion().getNodeLocations()[0].getNodeOffset(), macroLocation[0].getNodeOffset() );
            assertEquals( nodeLocation.getExpansion().getNodeLocations()[0].getNodeLength(), macroLocation[0].getNodeLength() );
            
            IASTPointer po = (IASTPointer) d.getPointerOperators()[0];
            assertFalse( po.isConst() );
            assertFalse( po.isVolatile() );
            IASTMacroExpansionLocation pointerLocation = (IASTMacroExpansionLocation) po.getNodeLocations()[0];
            assertEquals( pointerLocation.getNodeOffset(), 0 );
            assertEquals( pointerLocation.getNodeLength(), 1 );
            assertEquals( pointerLocation.getExpansion().getNodeLocations()[0].getNodeOffset(), macroLocation[0].getNodeOffset() );
            assertEquals( pointerLocation.getExpansion().getNodeLocations()[0].getNodeLength(), macroLocation[0].getNodeLength() );
            assertEqualsMacros( pointerLocation.getExpansion().getMacroDefinition(), nodeLocation.getExpansion().getMacroDefinition() );
        }
    }    
    
    public void testObjectMacroExpansionPartialDeclSpec() throws Exception
    {
        StringBuffer buffer = new StringBuffer( "#define XYZ const\n"); //$NON-NLS-1$
        buffer.append( "XYZ int var;"); //$NON-NLS-1$
        String code = buffer.toString();
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            IASTPreprocessorObjectStyleMacroDefinition defXYZ = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[0];
            IASTSimpleDeclaration var = (IASTSimpleDeclaration) tu.getDeclarations()[0];
            IASTSimpleDeclSpecifier declSpec = (IASTSimpleDeclSpecifier) var.getDeclSpecifier();
            IASTNodeLocation [] declSpecLocations = declSpec.getNodeLocations();
            assertEquals( declSpecLocations.length, 2 );
            IASTMacroExpansionLocation expansion = (IASTMacroExpansionLocation) declSpecLocations[0];
            assertEqualsMacros( defXYZ, expansion.getExpansion().getMacroDefinition() );
            assertEquals( expansion.getNodeOffset(), 0 );
            assertEquals( expansion.getNodeLength(), 1 );
            IASTNodeLocation [] expansionLocations = expansion.getExpansion().getNodeLocations();
            assertEquals( expansionLocations.length, 1 );
            assertTrue( expansionLocations[0] instanceof IASTFileLocation );
            assertEquals( expansionLocations[0].getNodeOffset(), code.indexOf( "XYZ int")); //$NON-NLS-1$
            assertEquals( expansionLocations[0].getNodeLength(), "XYZ".length()); //$NON-NLS-1$
            IASTFileLocation second = (IASTFileLocation) declSpecLocations[1];
            assertEquals( second.getNodeOffset(), code.indexOf( " int") ); //$NON-NLS-1$
            assertEquals( second.getNodeLength(), " int".length() ); //$NON-NLS-1$
        }        
    }
    
    public void testObjectMacroExpansionNested() throws Exception
    {
        StringBuffer buffer = new StringBuffer( "#define XYZ const\n"); //$NON-NLS-1$
        buffer.append( "#define PO *\n"); //$NON-NLS-1$
        buffer.append( "#define C_PO PO XYZ\n"); //$NON-NLS-1$
        buffer.append( "int C_PO var;"); //$NON-NLS-1$
        String code = buffer.toString();
        
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            final IASTPreprocessorMacroDefinition[] macroDefinitions = tu.getMacroDefinitions();
            IASTPreprocessorMacroDefinition XYZ = macroDefinitions[0];
            IASTPreprocessorMacroDefinition PO = macroDefinitions[1];
            IASTPreprocessorMacroDefinition C_PO = macroDefinitions[2];
            IASTSimpleDeclaration var = (IASTSimpleDeclaration) tu.getDeclarations()[0];
            assertTrue( var.getDeclarators()[0].getPointerOperators().length > 0 );
            IASTNodeLocation [] locations = var.getNodeLocations();
            assertEquals( 3, locations.length);
            IASTFileLocation start_loc = (IASTFileLocation) locations[0];
            assertEquals( start_loc.getNodeOffset(), code.indexOf( "int") ); //$NON-NLS-1$
            assertEquals( start_loc.getNodeLength(), "int ".length()); //$NON-NLS-1$
            IASTMacroExpansionLocation mac_loc = (IASTMacroExpansionLocation) locations[1];
            final IASTPreprocessorMacroDefinition C_PO2 = mac_loc.getExpansion().getMacroDefinition();
            assertEqualsMacros( C_PO, C_PO2 );
            assertEquals( 0, mac_loc.getNodeOffset());
            assertEquals( 2, mac_loc.getNodeLength() );
            IASTFileLocation end_loc = (IASTFileLocation) locations[2];
            assertEquals( code.indexOf( " var"), end_loc.getNodeOffset() );  //$NON-NLS-1$
            assertEquals( " var;".length(), end_loc.getNodeLength() ); //$NON-NLS-1$
        }
    }

    public void testObjectMacroExpansionComplex() throws Exception
    {
        StringBuffer buffer = new StringBuffer( "#define XYZ const\n"); //$NON-NLS-1$
        buffer.append( "#define PO *\n"); //$NON-NLS-1$
        buffer.append( "#define C_PO PO XYZ\n"); //$NON-NLS-1$
        buffer.append( "#define IT int\n"); //$NON-NLS-1$
        buffer.append( "#define V var\n"); //$NON-NLS-1$
        buffer.append( "XYZ IT C_PO C_PO V;"); //$NON-NLS-1$
        String code = buffer.toString();
        
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            IASTPreprocessorObjectStyleMacroDefinition XYZ = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[0];
//            IASTPreprocessorObjectStyleMacroDefinition PO = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[1];
            IASTPreprocessorObjectStyleMacroDefinition C_PO = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[2];
            IASTPreprocessorObjectStyleMacroDefinition IT = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[3];
            IASTPreprocessorObjectStyleMacroDefinition V = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[4];
            
            IASTSimpleDeclaration var = (IASTSimpleDeclaration) tu.getDeclarations()[0];
            final IASTNodeLocation[] nodeLocations = var.getNodeLocations();
            
            assertEquals( 10, nodeLocations.length );
            IASTMacroExpansionLocation first_loc = (IASTMacroExpansionLocation) nodeLocations[0];
            assertEqualsMacros( first_loc.getExpansion().getMacroDefinition(), XYZ );
            IASTFileLocation second_loc = (IASTFileLocation) nodeLocations[1];
            assertEquals( 1, second_loc.getNodeLength() );
            IASTMacroExpansionLocation third_loc = (IASTMacroExpansionLocation) nodeLocations[2];
            assertEqualsMacros( third_loc.getExpansion().getMacroDefinition(), IT );
            IASTFileLocation fourth_loc = (IASTFileLocation) nodeLocations[3];
            assertEquals( 1, fourth_loc.getNodeLength() );
            IASTMacroExpansionLocation fifth_loc = (IASTMacroExpansionLocation) nodeLocations[4];
            assertEqualsMacros( fifth_loc.getExpansion().getMacroDefinition(), C_PO );
            IASTFileLocation sixth_loc = (IASTFileLocation) nodeLocations[5];
            assertEquals( 1, sixth_loc.getNodeLength() );
            IASTMacroExpansionLocation seventh_loc = (IASTMacroExpansionLocation) nodeLocations[6];
            assertEqualsMacros( seventh_loc.getExpansion().getMacroDefinition(), C_PO );
            IASTFileLocation eighth_loc = (IASTFileLocation) nodeLocations[7];
            assertEquals( 1, eighth_loc.getNodeLength() );
            IASTMacroExpansionLocation ninth_loc = (IASTMacroExpansionLocation) nodeLocations[8];
            assertEqualsMacros( ninth_loc.getExpansion().getMacroDefinition(), V );
            IASTFileLocation tenth_loc = (IASTFileLocation) nodeLocations[9];
            assertEquals( 1, tenth_loc.getNodeLength() );

            final IASTFileLocation flatLocation = var.getFileLocation();
            assertNotNull( flatLocation);
            assertEquals( code.indexOf("XYZ IT C_PO C_PO V;"), flatLocation.getNodeOffset() ); //$NON-NLS-1$
            assertEquals( "XYZ IT C_PO C_PO V;".length(), flatLocation.getNodeLength() ); //$NON-NLS-1$

            
        }        
    }
    
    public void testStdioBug() throws ParserException
    {
        StringBuffer buffer = new StringBuffer( "#define    _PTR        void *\n"); //$NON-NLS-1$
        buffer.append( "#define __cdecl __attribute__ ((__cdecl__))\n" ); //$NON-NLS-1$
        buffer.append( "#define _EXFUN(name, proto)     __cdecl name proto\n"); //$NON-NLS-1$
        buffer.append( "_PTR     _EXFUN(memchr,(const _PTR, int, size_t));\n"); //$NON-NLS-1$
        String code = buffer.toString();
        
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i], true, true);
            final IASTPreprocessorMacroDefinition[] macroDefinitions = tu.getMacroDefinitions();
            IASTPreprocessorObjectStyleMacroDefinition _PTR = (IASTPreprocessorObjectStyleMacroDefinition) macroDefinitions[0];
            IASTPreprocessorFunctionStyleMacroDefinition _EXFUN = (IASTPreprocessorFunctionStyleMacroDefinition) macroDefinitions[2];
            IASTSimpleDeclaration memchr = (IASTSimpleDeclaration) tu.getDeclarations()[0];
            IASTNodeLocation [] locations = memchr.getNodeLocations();
            assertEquals( locations.length, 4 );
            IASTMacroExpansionLocation loc_1 = (IASTMacroExpansionLocation) locations[0];
            assertEqualsMacros( _PTR, loc_1.getExpansion().getMacroDefinition() );
            IASTFileLocation loc_2 = (IASTFileLocation) locations[1];
            assertEquals( loc_2.getNodeOffset(), code.indexOf( "     _EXFUN(")); //$NON-NLS-1$
            assertEquals( loc_2.getNodeLength(), "     ".length() ); //$NON-NLS-1$
            IASTMacroExpansionLocation loc_3 = (IASTMacroExpansionLocation) locations[2];
            assertEqualsMacros( _EXFUN, loc_3.getExpansion().getMacroDefinition() );
            IASTFileLocation loc_4 = (IASTFileLocation) locations[3];
            assertEquals( loc_4.getNodeOffset(), code.indexOf( ";")); //$NON-NLS-1$
            assertEquals( loc_4.getNodeLength(), 1 );
            IASTFileLocation flat = memchr.getFileLocation();
            assertEquals( flat.getNodeOffset() , code.indexOf( "_PTR     _EXFUN(memchr,(const _PTR, int, size_t));")); //$NON-NLS-1$
            assertEquals( flat.getNodeLength(), "_PTR     _EXFUN(memchr,(const _PTR, int, size_t));".length() ); //$NON-NLS-1$
            
            IASTDeclarator d = memchr.getDeclarators()[0];
            IASTFileLocation f = d.getFileLocation();
            assertEquals( code.indexOf( "_PTR     _EXFUN(memchr,(const _PTR, int, size_t))"), f.getNodeOffset() ); //$NON-NLS-1$
            assertEquals( "_PTR     _EXFUN(memchr,(const _PTR, int, size_t))".length(), f.getNodeLength() ); //$NON-NLS-1$
        }        
    }
    
    private void assertEqualsMacros(IASTPreprocessorMacroDefinition fromExpansion, IASTPreprocessorMacroDefinition source) {
        assertEquals( fromExpansion.getExpansion(), source.getExpansion() );
        assertEquals( fromExpansion.getName().toString(), source.getName().toString() );
    }
    
    public void testMacroBindings() throws Exception
    {
        StringBuffer buffer = new StringBuffer( "#define ABC def\n"); //$NON-NLS-1$
        buffer.append( "int ABC;\n"); //$NON-NLS-1$
        buffer.append( "#undef ABC\n"); //$NON-NLS-1$
        buffer.append( "#define ABC ghi\n"); //$NON-NLS-1$
        buffer.append( "int ABC;\n"); //$NON-NLS-1$
        String code = buffer.toString();
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            IASTPreprocessorMacroDefinition [] macros = tu.getMacroDefinitions();
            assertEquals( macros.length, 2 );
            IASTPreprocessorObjectStyleMacroDefinition ABC1 = (IASTPreprocessorObjectStyleMacroDefinition) macros[0];
            IASTPreprocessorObjectStyleMacroDefinition ABC2 = (IASTPreprocessorObjectStyleMacroDefinition) macros[1];
            IMacroBinding binding1 = (IMacroBinding) ABC1.getName().resolveBinding();
            assertNotNull( binding1 );
            IMacroBinding binding2 = (IMacroBinding) ABC2.getName().resolveBinding();
            assertNotNull( binding2 );
            assertNotSame( binding1, binding2 );
            IASTName [] firstReferences = tu.getReferences( binding1 );
            IASTName [] firstDeclarations = tu.getDeclarationsInAST( binding1 );
            assertEquals( firstReferences.length, 2 );
            assertEquals( firstReferences[0].getPropertyInParent(), IASTPreprocessorMacroExpansion.EXPANSION_NAME );
            assertEquals( firstReferences[0].getParent().getParent(), tu );
            assertEquals( firstReferences[1].getPropertyInParent(), IASTPreprocessorStatement.MACRO_NAME );
            assertTrue( firstReferences[1].getParent() instanceof IASTPreprocessorUndefStatement );
            assertEquals( firstDeclarations.length, 1 );
            assertSame( ABC1.getName(), firstDeclarations[0] );
            IASTName [] secondReferences = tu.getReferences(binding2);
            IASTName [] secondDeclarations = tu.getDeclarationsInAST( binding2 );
            assertEquals( 1, secondReferences.length );
            assertEquals( secondReferences[0].getPropertyInParent(), IASTPreprocessorMacroExpansion.EXPANSION_NAME );
            assertEquals( secondReferences[0].getParent().getParent(), tu );
            assertSame( ABC2.getName(), secondDeclarations[0]);
        }
    }
    
    
    public void testBug90978() throws Exception {
        StringBuffer buffer = new StringBuffer( "#define MACRO mm\n"); //$NON-NLS-1$
        buffer.append( "int MACRO;\n"); //$NON-NLS-1$
        String code = buffer.toString();
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            IASTPreprocessorObjectStyleMacroDefinition MACRO = (IASTPreprocessorObjectStyleMacroDefinition) tu.getMacroDefinitions()[0];
            IASTName macro_name = MACRO.getName();
            IMacroBinding binding = (IMacroBinding) macro_name.resolveBinding();
            IASTName [] references = tu.getReferences( binding );
            assertEquals( references.length, 1 );
            IASTName reference = references[0];
            IASTNodeLocation [] nodeLocations = reference.getNodeLocations();
            assertEquals( nodeLocations.length, 1 );
            assertTrue( nodeLocations[0] instanceof IASTFileLocation );
            IASTFileLocation loc = (IASTFileLocation) nodeLocations[0];
            assertEquals( code.indexOf( "int MACRO") + "int ".length(), loc.getNodeOffset() ); //$NON-NLS-1$ //$NON-NLS-2$
            assertEquals( "MACRO".length(), loc.getNodeLength() ); //$NON-NLS-1$
        }
    }
    
    public void testBug94933() throws Exception {
        StringBuffer buffer = new StringBuffer( "#define API extern\n" ); //$NON-NLS-1$
        buffer.append( "#define MYAPI API\n"); //$NON-NLS-1$
        buffer.append( "MYAPI void func() {}" ); //$NON-NLS-1$
        String code = buffer.toString();
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            IASTFunctionDefinition f = (IASTFunctionDefinition) tu.getDeclarations()[0];
            assertNotNull( f.getFileLocation() ); 
        }
    }

    public void testFunctionMacroExpansionWithNameSubstitution_Bug173637() throws Exception
    {
        StringBuffer buffer = new StringBuffer( "#define PLUS5(x) (x+5)\n"); //$NON-NLS-1$
        buffer.append( "#define FUNCTION PLUS5 \n"); //$NON-NLS-1$
        buffer.append( "int var= FUNCTION(1);"); //$NON-NLS-1$
        String code = buffer.toString();
        
        for(int i = 0; i < languages.length; i++) {
            IASTTranslationUnit tu = parse(code, languages[i]);
            IASTSimpleDeclaration var = (IASTSimpleDeclaration) tu.getDeclarations()[0];
            IASTInitializerExpression initializer= (IASTInitializerExpression)var.getDeclarators()[0].getInitializer();
            IASTExpression expr= initializer.getExpression();
            assertNotNull(expr.getFileLocation()); 
            IASTNodeLocation [] locations = expr.getNodeLocations();
            assertEquals(1, locations.length);
            IASTMacroExpansionLocation macroExpansion = (IASTMacroExpansionLocation) locations[0];
            IASTNodeLocation[] expLocations= macroExpansion.getExpansion().getNodeLocations();
            assertEquals(1, expLocations.length);
            assertEquals(code.indexOf("FUNCTION(1)"), expLocations[0].getNodeOffset());
            assertEquals("FUNCTION(1)".length(), expLocations[0].getNodeLength());
        }
    }
    
    
    private void assertMacroLocation(IASTDeclaration decl, int index, int length) {
    	IASTSimpleDeclaration var = (IASTSimpleDeclaration) decl;
        IASTInitializerExpression initializer= (IASTInitializerExpression)var.getDeclarators()[0].getInitializer();
        IASTExpression expr= initializer.getExpression();
        assertNotNull(expr.getFileLocation()); 
        IASTNodeLocation [] locations = expr.getNodeLocations();
        assertEquals(1, locations.length);
        IASTMacroExpansionLocation macroExpansion = (IASTMacroExpansionLocation) locations[0];
        IASTNodeLocation[] expLocations= macroExpansion.getExpansion().getNodeLocations();
        assertEquals(1, expLocations.length);
        IASTFileLocation fileLocation = expLocations[0].asFileLocation();
        assertEquals(index, fileLocation.getNodeOffset());
        assertEquals(length, fileLocation.getNodeLength());
    }
    
    private void assertExpressionLocation(IASTDeclaration decl, int index, int length) {
    	IASTSimpleDeclaration var = (IASTSimpleDeclaration) decl;
    	IASTInitializerExpression initializer= (IASTInitializerExpression)var.getDeclarators()[0].getInitializer();
        IASTExpression expr= initializer.getExpression();
        IASTFileLocation fileLocation = expr.getFileLocation();
        assertNotNull(fileLocation); 
        assertEquals(index, fileLocation.getNodeOffset());
        assertEquals(length, fileLocation.getNodeLength());
    }
    
    
    public void testBug186257() throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append("typedef char STR; \n"); //$NON-NLS-1$
        sb.append("#define Nullstr Null(STR*) \n"); //$NON-NLS-1$
        sb.append("#define Null(x) ((x)NULL) \n"); //$NON-NLS-1$
        sb.append("int x = Nullstr; \n"); //$NON-NLS-1$
        sb.append("int y = whatever; \n"); //$NON-NLS-1$
        String code = sb.toString();

        for(int i = 0; i < languages.length; i++) {
	        IASTTranslationUnit tu = parse(code, languages[i]);
	        IASTDeclaration[] decls = tu.getDeclarations();
	        assertMacroLocation(decls[1], code.indexOf("Nullstr;"), "Nullstr".length()); //$NON-NLS-1$ //$NON-NLS-2$
	        assertExpressionLocation(decls[2], code.indexOf("whatever;"), "whatever".length()); //$NON-NLS-1$ //$NON-NLS-2$
        }
    }
    
    
    public void testArgumentExpansion() throws Exception {
    	StringBuffer sb = new StringBuffer();
    	sb.append("#define ADD(a,b, c) (a) + (b) + (c) \n"); //$NON-NLS-1$
    	sb.append("#define ONEYONENOE 111111   \n"); //$NON-NLS-1$
    	sb.append("#define TWO 2 \n"); //$NON-NLS-1$
    	sb.append("#define THREE 3 \n"); //$NON-NLS-1$
    	sb.append("int x = ADD(ONEYONENOE,TWO,  THREE); \n"); //$NON-NLS-1$
    	sb.append("int y = whatever; \n"); //$NON-NLS-1$
    	String code = sb.toString();
    	
    	for(int i = 0; i < languages.length; i++) {
	    	IASTTranslationUnit tu = parse(code, languages[i]);
	        IASTDeclaration[] decls = tu.getDeclarations();
	        assertMacroLocation(decls[0], code.indexOf("ADD(ONEYONENOE,TWO,  THREE)"), "ADD(ONEYONENOE,TWO,  THREE)".length()); //$NON-NLS-1$ //$NON-NLS-2$
	        assertExpressionLocation(decls[1], code.indexOf("whatever;"), "whatever".length()); //$NON-NLS-1$ //$NON-NLS-2$
    	}
    }
    
    
    public void testArgumentCapture() throws Exception {
    	StringBuffer sb = new StringBuffer();
    	sb.append("#define add(x,y) x + y \n"); //$NON-NLS-1$
    	sb.append("#define add2 add(x,   \n"); //$NON-NLS-1$
    	sb.append("int x = add2 z); \n"); //$NON-NLS-1$
    	sb.append("int y = whatever; \n"); //$NON-NLS-1$
    	String code = sb.toString();
    	
    	for(int i = 0; i < languages.length; i++) {
	    	IASTTranslationUnit tu = parse(code, languages[i]);
	        IASTDeclaration[] decls = tu.getDeclarations();
	        assertMacroLocation(decls[0], code.indexOf("add2 z);"), "add2 z)".length()); //$NON-NLS-1$ //$NON-NLS-2$
	        assertExpressionLocation(decls[1], code.indexOf("whatever;"), "whatever".length()); //$NON-NLS-1$ //$NON-NLS-2$
    	}
    }
    
    
    public void testFunctionMacroNotCalled() throws Exception {
    	StringBuffer sb = new StringBuffer();
    	sb.append("#define FUNCTION(x) x \n"); //$NON-NLS-1$
    	sb.append("#define YO FUNCTION \n"); //$NON-NLS-1$
    	sb.append("int x = YO; \n"); //$NON-NLS-1$
    	sb.append("int y = whatever; \n"); //$NON-NLS-1$
    	String code = sb.toString();
    	
    	for(int i = 0; i < languages.length; i++) {
	    	IASTTranslationUnit tu = parse(code, languages[i]);
	        IASTDeclaration[] decls = tu.getDeclarations();
	        assertMacroLocation(decls[0], code.indexOf("YO;"), "YO".length()); //$NON-NLS-1$ //$NON-NLS-2$
	        assertExpressionLocation(decls[1], code.indexOf("whatever;"), "whatever".length()); //$NON-NLS-1$ //$NON-NLS-2$
    	}
    }
    
    public void testBuildFunctionMacroName() throws Exception {
    	StringBuffer sb = new StringBuffer();
    	sb.append("#define FUN1(x) x \n"); //$NON-NLS-1$
    	sb.append("#define FUN1(x) x \n"); //$NON-NLS-1$
    	sb.append("#define MAKEFUN(num) FUN ## num \n"); //$NON-NLS-1$
    	sb.append("int x = MAKEFUN(1)(z); \n"); //$NON-NLS-1$
    	sb.append("int y = whatever; \n"); //$NON-NLS-1$
    	String code = sb.toString();
    	
    	for(int i = 0; i < languages.length; i++) {
	    	IASTTranslationUnit tu = parse(code, languages[i]);
	        IASTDeclaration[] decls = tu.getDeclarations();
	        assertMacroLocation(decls[0], code.indexOf("MAKEFUN(1)(z);"), "MAKEFUN(1)(z)".length()); //$NON-NLS-1$ //$NON-NLS-2$
	        assertExpressionLocation(decls[1], code.indexOf("whatever;"), "whatever".length()); //$NON-NLS-1$ //$NON-NLS-2$
    	}
    }

}
