project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/internal/cpp/epoc/engine/model/makefile/MakefileViewBase.java
author Ed Swartz <ed.swartz@nokia.com>
Wed, 02 Dec 2009 15:02:05 -0600
changeset 610 bfb3ab3f70f2
parent 0 fb279309251b
child 684 8e7900690341
permissions -rw-r--r--
Initial round of Unix portability fixes (using HostOS class), and fixes to EPOC engine unit tests.

/*
* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

package com.nokia.carbide.internal.cpp.epoc.engine.model.makefile;

import com.nokia.carbide.cpp.epoc.engine.DocumentFactory;
import com.nokia.carbide.cpp.epoc.engine.EpocEnginePlugin;
import com.nokia.carbide.cpp.epoc.engine.model.IData;
import com.nokia.carbide.cpp.epoc.engine.model.IOwnedModel;
import com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileViewBase;
import com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileViewConfiguration;
import com.nokia.carbide.cpp.epoc.engine.preprocessor.IIncludeFileLocator;
import com.nokia.carbide.internal.api.cpp.epoc.engine.dom.ASTFactory;
import com.nokia.carbide.internal.cpp.epoc.engine.model.ModelBase;
import com.nokia.carbide.internal.cpp.epoc.engine.model.ViewBase;
import com.nokia.cpp.internal.api.utils.core.*;

import org.eclipse.cdt.make.core.MakeCorePlugin;
import org.eclipse.cdt.make.core.makefile.*;
import org.eclipse.cdt.make.core.makefile.gnu.IVariableDefinition;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.text.*;
import org.eclipse.text.edits.*;

import java.io.*;
import java.net.URI;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class MakefileViewBase<Model extends IOwnedModel> extends ViewBase<Model> implements IMakefileViewBase {

	private IMakefile makefile;
	private Map<IPath, IDocument> shadowDocuments;
	private String eol;
	private HashMap<String, IPath> directiveFilenameToPathMap;
	private Set<IPath> referencedFiles;
	private VariableSubstitutionEngine engine;
	private IVariableLookupCallback engineSubstitutor;
	
	/**
	 * @param model
	 * @param parser
	 * @param viewConfiguration
	 */
	public MakefileViewBase(ModelBase model, IMakefileViewConfiguration viewConfiguration) {
		super(model, null, viewConfiguration);
		this.makefile = null;
		this.shadowDocuments = new HashMap<IPath, IDocument>();
		shadowDocuments.put(model.getPath(),
			DocumentFactory.createDocument(model.getDocument().get()));
		this.referencedFiles = new HashSet<IPath>();
	}
	
	private IDocument getMainShadowDocument() {
		return shadowDocuments.get(model.getPath());
	}
	
	private void refreshMakefile() {
		String text = getMainShadowDocument().get();
		
		eol = System.getProperty("line.separator"); //$NON-NLS-1$
		Pattern eolPattern = TextUtils.ANY_NEWLINE_MATCHING_PATTERN;
		Matcher matcher = eolPattern.matcher(text);
		if (matcher.find())
			eol = matcher.group(1);
	
		try {
			makefile.parse(URIUtil.toURI(getModel().getPath().toOSString()),
					makefile.getMakefileReaderProvider());
		} catch (IOException e) {
			EpocEnginePlugin.log(e);
		}
	}
		
	@Override
	public IPath[] getReferencedFiles() {
		return (IPath[]) referencedFiles.toArray(new IPath[referencedFiles.size()]);
	}
	
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.internal.cpp.epoc.engine.model.ViewBase#internalReparse()
	 */
	@Override
	protected Map<IPath, IDocument> internalReparse(Map<IPath, IDocument> overrideDocumentMap) {
		IPath modelPath = getModel().getPath();
		if (makefile == null) {
			String style = ((IMakefileViewConfiguration) getViewConfiguration()).getMakefileStyle();
			boolean isGnuStyle = style == null || style.equals("GNU"); //$NON-NLS-1$
			
			directiveFilenameToPathMap = new HashMap<String, IPath>();
			
			IMakefileReaderProvider provider = createMakefileReaderProvider(); 
			IDocument document = null;
			if (overrideDocumentMap != null) {
				document = overrideDocumentMap.get(modelPath);
			}
			if (document == null) {
				document = getModel().getDocument();
			}
			
			// prefetch the main document
			referencedFiles.clear();
			referencedFiles.add(modelPath);
			directiveFilenameToPathMap.put(modelPath.toOSString(), modelPath);

			IDocument shadowDocument = DocumentFactory.createDocument(document.get());
			shadowDocuments.put(modelPath, shadowDocument);
			
			String[] includeDirs = getIncludeDirs(getViewConfiguration().getViewParserConfiguration().getIncludeFileLocator());
			makefile = MakeCorePlugin.createMakefile(
					URIUtil.toURI(modelPath.toOSString()), 
					isGnuStyle, includeDirs,
					provider);
		} else {
			referencedFiles.clear();
			referencedFiles.add(modelPath);
			
			refreshMakefile();
			
			for (Iterator<Map.Entry<IPath, IDocument>> iter = shadowDocuments.entrySet().iterator(); 
				iter.hasNext() ;) {
				Map.Entry<IPath, IDocument> entry = iter.next();
				if (!referencedFiles.contains(entry.getKey()))
					iter.remove();
			}
			
		}

		// get non-model documents
		Map<IPath, IDocument> documentMap = new HashMap<IPath, IDocument>(shadowDocuments);
		documentMap.remove(modelPath);
		
		return documentMap;
	}
	
	/**
	 * Get the provider for the contents of the makefiles being parsed.
	 * @return
	 */
	private IMakefileReaderProvider createMakefileReaderProvider() {
		return new IMakefileReaderProvider() {

			// read from disk for unknown documents, else fetch from the shadow map
			public Reader getReader(String filename) throws IOException {
				
				IPath path = directiveFilenameToPathMap.get(filename);
				if (path == null) {
					path = new Path(filename);
					if (!path.toFile().exists())
						throw new FileNotFoundException(filename);
					
					File file = path.toFile().getCanonicalFile();	// may throw
					
					// remember the canonical mapping
					path = new Path(file.getAbsolutePath());
					directiveFilenameToPathMap.put(filename, path);
				}
				
				referencedFiles.add(path);
				
				// now get the shadow document or load it for the first time
				IDocument document = shadowDocuments.get(path);
				if (document == null) {
					// see if model knows about it
					document = getModel().getDocument(path);
					
					if (document == null) {
						// get contents from disk
						char[] contents = null;
						try {
							contents = FileUtils.readFileContents(path.toFile(), null);
							document = DocumentFactory.createDocument(
									new String(contents));
							getModel().setDocument(path, document);
							
						} catch (CoreException e) {
							EpocEnginePlugin.log(e);
							throw new FileNotFoundException(e.getMessage());
						}
					}
					shadowDocuments.put(path, 
							DocumentFactory.createDocument(document.get()));
				}
				
				return new StringReader(document.get());
			}

			public Reader getReader(URI fileURI) throws IOException {
				return getReader(URIUtil.toPath(fileURI).toOSString());
			}
		};
	}

	/**
	 * Get the include paths scanned.
	 * @param includeFileLocator
	 * @return
	 */
	private String[] getIncludeDirs(IIncludeFileLocator includeFileLocator) {
		File[] systemDirs = includeFileLocator.getSystemPaths();
		if (systemDirs == null)
			systemDirs = new File[0];
		File[] userDirs = includeFileLocator.getUserPaths();
		if (userDirs == null)
			userDirs = new File[0];
		String[] strings = new String[1 + systemDirs.length + userDirs.length];
		int idx = 0;
		strings[idx++] = getModel().getPath().removeLastSegments(1).toFile().getAbsolutePath();
		for (File file : userDirs) {
			strings[idx++] = file.getAbsolutePath();
		}
		for (File file : systemDirs) {
			strings[idx++] = file.getAbsolutePath();
		}
		return strings;
	}

	/* (non-Javadoc)
	 * @see com.nokia.carbide.internal.cpp.epoc.engine.model.ViewBase#internalRevertChanges()
	 */
	@Override
	protected void internalRevertChanges() {
		for (Map.Entry<IPath, IDocument> entry : shadowDocuments.entrySet()) {
			entry.getValue().set(getModel().getDocument(entry.getKey()).get());
		}
		refreshMakefile();
	}

	/* (non-Javadoc)
	 * @see com.nokia.carbide.internal.cpp.epoc.engine.model.ViewBase#internalHasChanges()
	 */
	@Override
	protected boolean internalHasChanges() {
		for (Map.Entry<IPath, IDocument> entry : shadowDocuments.entrySet()) {
			IDocument origDocument = getModel().getDocument(entry.getKey());
			IDocument currDocument = entry.getValue();
			if (origDocument == null || !origDocument.get().equals(currDocument.get()))
				return true;
		}
		return false;
	}

	/**
	 */
	protected void internalCommit() {
		model.lock();
		model.lockDocuments();
		// just copy shadow document to new document; we've been updating that all along
		for (Map.Entry<IPath, IDocument> entry : shadowDocuments.entrySet()) {
			IDocument origDocument = getModel().getDocument(entry.getKey());
			IDocument currDocument = entry.getValue();
			origDocument.set(currDocument.get());
		}		
		model.unlockDocuments();
		model.unlock();
		revert();
		model.desyncOtherViews(this);
		model.fireViewChanged(this);
	}
	
	@Override
	public boolean merge() {
		return true;
	}

	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#getMakefile()
	 */
	public IMakefile getMakefile() {
		return makefile;
	}

	private interface IDirectiveVisitor {
		void visit(IDirective directive);
	}
	
	private void accept(IDirective directive, IDirectiveVisitor visitor) {
		visitor.visit(directive);
		if (directive instanceof IParent) {
			IDirective[] kids = ((IParent)directive).getDirectives();
			for (IDirective kid : kids)
				accept(kid, visitor);
		}
	}

	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#getEOL()
	 */
	public String getEOL() {
		return eol;
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#getAllMacroDefinitions()
	 */
	public IMacroDefinition[] getAllMacroDefinitions() {
		final List<IMacroDefinition> list = new ArrayList<IMacroDefinition>();
		accept(makefile, new IDirectiveVisitor() {

			public void visit(IDirective directive) {
				if (directive instanceof IMacroDefinition) {
					// don't include exports as they would override the real macro definition
					if (directive instanceof IVariableDefinition) {
						if (((IVariableDefinition)directive).isExport()) {
							return;
						}
					}
					list.add((IMacroDefinition) directive);
				}
			}
			
		});
		return (IMacroDefinition[]) list.toArray(new IMacroDefinition[list.size()]);
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#getAllMacroDefinitions(java.lang.String)
	 */
	public IMacroDefinition[] getAllMacroDefinitions(final String name) {
		final List<IMacroDefinition> list = new ArrayList<IMacroDefinition>();
		accept(makefile, new IDirectiveVisitor() {

			public void visit(IDirective directive) {
				if (directive instanceof IMacroDefinition) {
					IMacroDefinition def = (IMacroDefinition) directive;
					if (def.getName().equals(name))
						list.add((IMacroDefinition) directive);
				}
			}
			
		});
		return (IMacroDefinition[]) list.toArray(new IMacroDefinition[list.size()]);
	}
	
	protected String getProgramMatcherPattern(String program) {
		String ext = ""; //$NON-NLS-1$
		program = makefile.expandString(program, true);
		if (HostOS.IS_WIN32) {
			ext = ".exe"; //$NON-NLS-1$
			if (program.length() > 4 && program.substring(program.length() - 4).equalsIgnoreCase(ext)) {
				program = program.substring(0, program.length() - 4);
			}
		}
		
		return "(\\s*|.*/|.*\\\\)" + program + "(" + ext + ")?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#findCommandsInvoking(java.lang.String)
	 */
	public ICommand[] findCommandsInvoking(String program) {
		List<ICommand> commands = new ArrayList<ICommand>();
		IRule[] rules = makefile.getRules();
		
		String patternS = getProgramMatcherPattern(program);
		Pattern pattern = Pattern.compile(patternS + "(\\s+.*|$)",  //$NON-NLS-1$
				Pattern.CASE_INSENSITIVE + Pattern.DOTALL);

		for (IRule rule : rules) {
			for (ICommand command : rule.getCommands()) {
				String cmd = makefile.expandString(command.toString(), true);
				if (pattern.matcher(cmd).matches()) {
					commands.add(command);
				}
			}
		}
		return (ICommand[]) commands.toArray(new ICommand[commands.size()]);
	}

	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#getRuleForTarget(java.lang.String,boolean)
	 */
	public ITargetRule findRuleForTarget(String target, boolean exactMatch) {
		ITargetRule match = null;
		File targetFile = new File(target);
		ITargetRule[] rules = makefile.getTargetRules();
		for (ITargetRule rule : rules) {
			File ruleFile = new File(rule.getTarget().toString());
			if (exactMatch && ruleFile.equals(targetFile)) 
				match = rule;
			else if (!exactMatch && ruleFile.getName().equalsIgnoreCase(targetFile.getName())) 
				match = rule;
		}
		return match;
	}

	protected IRegion getDirectiveRegion(IDirective directive) {
		try {
			IDocument shadowDocument = getDirectiveShadowDocument(directive);
			IRegion start = shadowDocument.getLineInformation(directive.getStartLine() - 1);
			IRegion end = shadowDocument.getLineInformation(directive.getEndLine() - 1);
			int endOffset = end.getOffset() + end.getLength();
			String eol = shadowDocument.getLineDelimiter(directive.getEndLine() - 1);
			if (eol != null)
				endOffset += eol.length();
			return new Region(start.getOffset(), endOffset - start.getOffset());
		} catch (BadLocationException e) {
			return null;
		}
	}

	/**
	 * @param directive
	 * @return
	 */
	private IDocument getDirectiveShadowDocument(IDirective directive) {
		IPath path = directiveFilenameToPathMap.get(URIUtil.toPath(directive.getMakefile().getFileURI()).toOSString());
		Check.checkState(path != null);
		
		return shadowDocuments.get(path);
	}

	/**
	 * Get the region where a target rule's target and dependencies live
	 * @param directive
	 * @param target
	 * @return region or null
	 */
	protected IRegion getTargetRegion(ITargetRule targetRule) {
		IRegion region = getDirectiveRegion(targetRule);
		if (region == null)
			return null;
		
		int idx = 0;
		String text;
		try {
			text = getDirectiveShadowDocument(targetRule).get(region.getOffset(), region.getLength());
		} catch (BadLocationException e) {
			return null;
		}
		while (idx < text.length()) {
			char ch = text.charAt(idx);
			// ignore catenated lines
			if (ch == '\\') {
				if (idx + 1 < text.length()) {
					char next = text.charAt(idx + 1);
					if (next == '\n' || next == '\r') {
						idx += 2;
						if (next == '\r' && idx < text.length() && text.charAt(idx) == '\n')
							idx++;
						continue;
					}
				}
			}
			if (ch == '\n' || ch == '\r') {
				// consume
				idx++;
				if (ch == '\r' && idx < text.length() && text.charAt(idx) == '\n')
					idx++;
				break;
			}
			idx++;
		}
		return new Region(region.getOffset(), idx);
	}
	
	private void applyEdit(IDocument document, TextEdit edit) {
		try {
			edit.apply(document, TextEdit.UPDATE_REGIONS);
		} catch (MalformedTreeException e) {
			EpocEnginePlugin.log(e);
			Check.checkState(false);
		} catch (BadLocationException e) {
			EpocEnginePlugin.log(e);
			Check.checkState(false);
		}
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#appendText(org.eclipse.cdt.make.core.makefile.IDirective, java.lang.String)
	 */
	public void appendText(String line) {
		insertTextBefore(line, null);
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#insertLine(org.eclipse.cdt.make.core.makefile.IDirective, java.lang.String)
	 */
	public void insertText(IDirective directive, String line) {
		IRegion region = new Region(0, 0);
		IDocument shadowDocument = getMainShadowDocument();
		if (directive != null) {
			region = getDirectiveRegion(directive);
			shadowDocument = getDirectiveShadowDocument(directive);
		}
		Check.checkArg(region);
		TextEdit edit = new InsertEdit(region.getOffset() + region.getLength(), line);
		applyEdit(shadowDocument, edit);
		refreshMakefile();
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#insertLineBefore(java.lang.String, org.eclipse.cdt.make.core.makefile.IDirective)
	 */
	public void insertTextBefore(String line, IDirective directive) {
		IDocument shadowDocument = getMainShadowDocument();
		IRegion region = new Region(shadowDocument.getLength(), 0);
		if (directive != null) {
			shadowDocument = getDirectiveShadowDocument(directive);
			region = getDirectiveRegion(directive);
		}

		Check.checkArg(region);
		TextEdit edit = new InsertEdit(region.getOffset(), line);
		applyEdit(shadowDocument, edit);
		refreshMakefile();
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#deleteDirective(IDirective)
	 */
	public void deleteDirective(IDirective directive) {
		IDocument document = getDirectiveShadowDocument(directive);
		Check.checkArg(document);
		IRegion region = getDirectiveRegion(directive);
		Check.checkArg(region);
		TextEdit edit = new DeleteEdit(region.getOffset(), region.getLength());
		applyEdit(document, edit);
		refreshMakefile();
	}

	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#replaceDirective(org.eclipse.cdt.make.core.makefile.IDirective, java.lang.String)
	 */
	public void replaceDirective(IDirective directive, String text) {
		IDocument document = getDirectiveShadowDocument(directive);
		Check.checkArg(document);
		IRegion region = getDirectiveRegion(directive);
		Check.checkArg(region);
		TextEdit edit = new ReplaceEdit(region.getOffset(), region.getLength(), text);
		applyEdit(document, edit);
		refreshMakefile();
	}
	
	protected void replaceTarget(ITargetRule targetRule, String text) {
		IDocument document = getDirectiveShadowDocument(targetRule);
		Check.checkArg(document);
		IRegion region = getTargetRegion(targetRule);
		Check.checkArg(region);
		TextEdit edit = new ReplaceEdit(region.getOffset(), region.getLength(), text);
		applyEdit(document, edit);
		refreshMakefile();
	}

	public String expandAllMacrosInString(String text) {
		Map<String, String> vars = getAllDefs();
		return substituteMacros(vars, text);
		
	}

	/**
	 * @return
	 */
	private Map<String, String> getAllDefs() {
		Map<String, String> vars = new HashMap<String, String>();
		IMacroDefinition[] macroDefs = getAllMacroDefinitions();
		for (IDirective dir : macroDefs) {
			IMacroDefinition def = (IMacroDefinition) dir;
			vars.put(def.getName(), def.getValue().toString());
		}
		return vars;
	}

	private String substituteMacros(final Map<String, String> vars, String text) {
		if (engine == null) {
			engine = new VariableSubstitutionEngine(null, null);
			engine.allowRecursion(true);
			engine.setVariableToken('(');
			
			engineSubstitutor = new IVariableLookupCallback() {
				
				public Object getValue(String var) {
					String value = vars.get(var);
					if (value == null)
						return null;
					if (HostOS.IS_UNIX)
						value = HostOS.convertPathToUnix(value);
					return value;
				}
			};
		}
		return engine.substitute(engineSubstitutor, text);
	}

	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView#unexpandMacros(java.lang.String, java.lang.String[])
	 */
	public String unexpandMacros(String text, boolean exhaustive) {
		/*for (String macroName : macroNames) {
			IDefine[] macros = getAllMacroDefinitions(macroName);
			for (IDefine macro : macros) {
				text = unexpand(text, macro);
			}
		}
		if (exhaustive) {
		*/
		IMacroDefinition[] otherDefs;
		if (exhaustive)
			otherDefs = getAllMacroDefinitions();
		else
			otherDefs = makefile.getMacroDefinitions();
		
		boolean changed;
		do {
			changed = false;
			for (IMacroDefinition def : otherDefs) {
				String newText = unexpand(text, def);
				if (!newText.equals(text)) {
					changed = true;
					text = newText;
				}
			}
		} while (changed);
		//}
		return text;
	}

	/**
	 * Get the length of text outside variables.
	 * @param text
	 * @return
	 */
	private int constantTextLength(String text) {
		text = text.replaceAll("\\$\\(.*?\\)", ""); //$NON-NLS-1$ //$NON-NLS-2$
		return text.length();

	}
	private String unexpand(String text, IMacroDefinition macro) {
		String source = Pattern.quote(makefile.expandString(macro.getValue().toString(), true));
		String replacement = Matcher.quoteReplacement("$(" + macro.getName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
		
		// try replacing into current string
		String unexpandedText = text.replaceAll(source, replacement);
		if (constantTextLength(unexpandedText) < constantTextLength(text))
			return unexpandedText;
		
		// if not, re-expand everything and try again
		String expandedText = makefile.expandString(text, true);
		unexpandedText = expandedText.replaceAll(source, replacement);
		if (constantTextLength(unexpandedText) < constantTextLength(text))
			return unexpandedText;
		
		return text;
	}

	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileViewBase#expandAllMacrosInRuleString(java.lang.String, org.eclipse.cdt.make.core.makefile.ITargetRule)
	 */
	public String expandAllMacrosInRuleString(String text, ITargetRule rule) {
		text = text.replaceAll("\\$<", Matcher.quoteReplacement(rule.getTarget().toString())); //$NON-NLS-1$
		String[] prereqs = rule.getPrerequisites();
		if (prereqs.length > 0)
			text = text.replaceAll("\\$<", prereqs[0]); //$NON-NLS-1$
		text = text.replaceAll("\\$@", Matcher.quoteReplacement(TextUtils.catenateStrings(prereqs, " "))); //$NON-NLS-1$ //$NON-NLS-2$

		Map<String, String> vars = getAllDefs();
		text = substituteMacros(vars, text);
		
		return text;
	}
	
	public String unexpandMacros(String text, String[] macroNames) {
		for (String macroName : macroNames) {
			IMacroDefinition[] macros = getMakefile().getMacroDefinitions(macroName);
			for (IMacroDefinition macro : macros) {
				text = unexpand(text, macro);
			}
		}
		return text;
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.internal.cpp.epoc.engine.model.ViewBase#addViewSpecificMessages(java.util.List)
	 */
	@Override
	protected void addViewSpecificMessages(List<IMessage> messageList) {
		IPath fullPath = getModel().getPath();
		IDirective[] directives = getMakefile().getDirectives();
		for (IDirective directive : directives) {
			if (directive instanceof IBadDirective) {
				String text = directive.toString();
				messageList.add(ASTFactory.createMessage(
								IMessage.ERROR,
								"MakefileViewBase.BadDirective", //$NON-NLS-1$
								new Object[] { text }, 
								new MessageLocation(fullPath, directive.getStartLine(), 0)));
			}
		}
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.cpp.epoc.engine.model.IView#getData()
	 */
	public IData getData() {
		return null;
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.internal.cpp.epoc.engine.model.ViewBase#convertModelToProjectPath(org.eclipse.core.runtime.IPath)
	 */
	@Override
	public IPath convertModelToProjectPath(IPath modelPath) {
		if (isAbsolutePath(modelPath) || modelPath.toString().startsWith("$")) //$NON-NLS-1$
			return modelPath;

		return super.convertModelToProjectPath(modelPath);
	}
	
	/* (non-Javadoc)
	 * @see com.nokia.carbide.internal.cpp.epoc.engine.model.ViewBase#convertProjectToModelPath(org.eclipse.core.runtime.IPath)
	 */
	@Override
	public IPath convertProjectToModelPath(IPath prjPath) {
		if (isAbsolutePath(prjPath) || prjPath.toString().startsWith("$")) //$NON-NLS-1$
			return prjPath;

		return super.convertProjectToModelPath(prjPath);
	}
	
}