/******************************************************************************* * Copyright (c) 2009, 2016 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 Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.core.codeassist.contexts; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.dltk.core.*; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.php.core.PHPVersion; import org.eclipse.php.core.codeassist.CompletionCompanion; import org.eclipse.php.core.codeassist.ICompletionContext; import org.eclipse.php.core.project.ProjectOptions; import org.eclipse.php.internal.core.Logger; import org.eclipse.php.internal.core.PHPCorePlugin; import org.eclipse.php.internal.core.codeassist.IPHPCompletionRequestor; import org.eclipse.php.internal.core.documentModel.parser.PHPRegionContext; import org.eclipse.php.internal.core.documentModel.parser.regions.IPHPScriptRegion; import org.eclipse.php.internal.core.documentModel.parser.regions.PHPRegionTypes; import org.eclipse.php.internal.core.documentModel.partitioner.PHPPartitionTypes; import org.eclipse.php.internal.core.format.PHPHeuristicScanner; import org.eclipse.php.internal.core.util.text.PHPTextSequenceUtilities; import org.eclipse.php.internal.core.util.text.TextSequence; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; import org.eclipse.wst.sse.core.internal.provisional.exceptions.ResourceAlreadyExists; import org.eclipse.wst.sse.core.internal.provisional.text.*; /** * This is an abstract completion context containing all common utilities. * * @author michael */ public abstract class AbstractCompletionContext implements ICompletionContext { public static final int NONE = 0; public static final int TRAIT_NAME = 1; public static final int TRAIT_KEYWORD = 2; private CompletionCompanion companion; private CompletionRequestor requestor; private ISourceModule sourceModule; private int offset; private PHPVersion phpVersion; private IStructuredDocument document; private IStructuredDocumentRegion structuredDocumentRegion; private ITextRegionCollection regionCollection; private IPHPScriptRegion phpScriptRegion; private String partitionType; public void init(CompletionCompanion companion) { this.companion = companion; } protected CompletionCompanion getCompanion() { return companion; } public boolean isValid(ISourceModule sourceModule, int offset, CompletionRequestor requestor) { if (sourceModule == null) { throw new IllegalArgumentException(); } this.requestor = requestor; this.sourceModule = sourceModule; this.offset = offset; this.phpVersion = ProjectOptions.getPHPVersion(sourceModule.getScriptProject().getProject()); try { this.document = determineDocument(sourceModule, requestor); if (this.document != null) { structuredDocumentRegion = determineStructuredDocumentRegion(document, offset); if (structuredDocumentRegion != null) { regionCollection = determineRegionCollection(document, structuredDocumentRegion, offset); if (regionCollection != null) { phpScriptRegion = determinePHPRegion(document, regionCollection, offset); if (phpScriptRegion != null) { partitionType = determinePartitionType(regionCollection, phpScriptRegion, offset); if (partitionType != null) { String prefix = getPrefix(); if (prefix.length() > 0 && (!Character.isJavaIdentifierStart(prefix.charAt(0)) && prefix.charAt(0) != '\\')) { return false; } return true; } } } } } } catch (Exception e) { PHPCorePlugin.log(e); } return false; } public boolean isExclusive() { return false; } /** * Determines the structured document region of the place in PHP code where * completion was requested * * @return structured document region or <code>null</code> in case it could * not be determined */ protected IStructuredDocumentRegion determineStructuredDocumentRegion(IStructuredDocument document, int offset) { IStructuredDocumentRegion sdRegion = null; int lastOffset = offset; // find the structured document region: while (sdRegion == null && lastOffset >= 0) { sdRegion = document.getRegionAtCharacterOffset(lastOffset); lastOffset--; } return sdRegion; } /** * Determines the relevant region collection of the place in PHP code where * completion was requested * * @return text region collection or <code>null</code> in case it could not * be determined */ protected ITextRegionCollection determineRegionCollection(IStructuredDocument document, IStructuredDocumentRegion sdRegion, int offset) { ITextRegionCollection regionCollection = sdRegion; ITextRegion textRegion = determineTextRegion(document, sdRegion, offset); if (textRegion instanceof ITextRegionContainer) { regionCollection = (ITextRegionContainer) textRegion; } return regionCollection; } /** * Determines the text region from the text region collection and offset * * @param regionCollection * @param offset */ protected ITextRegion determineTextRegion(IStructuredDocument document, ITextRegionCollection regionCollection, int offset) { ITextRegion textRegion; // in case we are at the end of the document, asking for completion if (offset == document.getLength()) { textRegion = regionCollection.getLastRegion(); } else { textRegion = regionCollection.getRegionAtCharacterOffset(offset); } return textRegion; } /** * Determines the PHP script region of PHP code where completion was * requested * * @return php script region or <code>null</code> in case it could not be * determined */ protected IPHPScriptRegion determinePHPRegion(IStructuredDocument document, ITextRegionCollection regionCollection, int offset) { ITextRegion textRegion = determineTextRegion(document, regionCollection, offset); IPHPScriptRegion phpScriptRegion = null; if (textRegion != null) { if (textRegion.getType() == PHPRegionContext.PHP_OPEN) { return null; } else if (textRegion.getType() == PHPRegionContext.PHP_CLOSE) { if (regionCollection.getStartOffset(textRegion) == offset) { textRegion = regionCollection.getRegionAtCharacterOffset(offset - 1); } else { return null; } } } if (textRegion instanceof IPHPScriptRegion) { phpScriptRegion = (IPHPScriptRegion) textRegion; } return phpScriptRegion; } /** * Determines the partition type of the code where cursor is located. * * @param regionCollection * Text region collection * @param phpScriptRegion * PHP script region * @param offset * @return partition type (see {@link PHPRegionTypes}) * @throws BadLocationException */ protected String determinePartitionType(ITextRegionCollection regionCollection, IPHPScriptRegion phpScriptRegion, int offset) throws BadLocationException { int internalOffset = getOffset(offset, regionCollection, phpScriptRegion); String partitionType = phpScriptRegion.getPartition(internalOffset); // if we are at the begining of multi-line comment or docBlock then we // should get completion. if (partitionType == PHPPartitionTypes.PHP_MULTI_LINE_COMMENT || partitionType == PHPPartitionTypes.PHP_DOC) { String regionType = phpScriptRegion.getPHPToken(internalOffset).getType(); if (PHPPartitionTypes.isPHPMultiLineCommentStartRegion(regionType) || PHPPartitionTypes.isPHPDocStartRegion(regionType)) { if (phpScriptRegion.getPHPToken(internalOffset).getStart() == internalOffset) { partitionType = phpScriptRegion.getPartition(internalOffset - 1); } } } return partitionType; } /** * Determines the document associated with the editor where code assist has * been invoked. * * @param module * Source module ({@link ISourceModule}) * @param requestor * Completion requestor ({@link CompletionRequestor}) * @return structured document or <code>null</code> if it couldn't be found * @throws CoreException * @throws IOException * @throws ResourceAlreadyExists */ protected IStructuredDocument determineDocument(ISourceModule module, CompletionRequestor requestor) throws ResourceAlreadyExists, IOException, CoreException { IStructuredDocument document = null; if (requestor instanceof IPHPCompletionRequestor) { IDocument d = ((IPHPCompletionRequestor) requestor).getDocument(); if (d instanceof IStructuredDocument) { document = (IStructuredDocument) d; } } if (document == null) { IStructuredModel structuredModel = null; try { IFile file = (IFile) module.getResource(); if (file != null) { if (file.exists()) { structuredModel = StructuredModelManager.getModelManager().getExistingModelForRead(file); if (structuredModel != null) { document = structuredModel.getStructuredDocument(); } else { document = StructuredModelManager.getModelManager().createStructuredDocumentFor(file); } } else { document = StructuredModelManager.getModelManager().createNewStructuredDocumentFor(file); document.set(module.getSource()); } } } finally { if (structuredModel != null) { structuredModel.releaseFromRead(); } } } return document; } /** * Returns PHP version of the file where code assist was requested * * @return PHP version * @see #isValid(ISourceModule, int, CompletionRequestor) */ public PHPVersion getPHPVersion() { return phpVersion; } /** * Returns the file where code assist was requested * * @return source module * @see #isValid(ISourceModule, int, CompletionRequestor) */ public ISourceModule getSourceModule() { return sourceModule; } /** * Returns document associated with the editor where code assist was * requested * * @return document * @see #isValid(ISourceModule, int, CompletionRequestor) */ public IStructuredDocument getDocument() { return document; } /** * Returns the relevant region collection of the place in PHP code where * completion was requested * * @return text region collection * @see #isValid(ISourceModule, int, CompletionRequestor) */ public ITextRegionCollection getRegionCollection() { return regionCollection; } /** * Returns the PHP script region of PHP code where completion was requested * * @return php script region (see {@link IPHPScriptRegion}) * @see #isValid(ISourceModule, int, CompletionRequestor) */ public IPHPScriptRegion getPHPScriptRegion() { return phpScriptRegion; } /** * Returns partition type of the code where cursor is located. * * @return partition type (see {@link PHPRegionTypes}) * @see #isValid(ISourceModule, int, CompletionRequestor) */ public String getPartitionType() { return partitionType; } /** * Returns the statement text that is before the cursor * * @return statement text * @see #isValid(ISourceModule, int, CompletionRequestor) */ public TextSequence getStatementText() { return PHPTextSequenceUtilities.getStatement(offset, structuredDocumentRegion, true); } public TextSequence getStatementText(int offset) { return PHPTextSequenceUtilities.getStatement(offset, structuredDocumentRegion, true); } /** * Returns whether there are whitespace characters before the cursor where * code assist was being invoked * * @return <code>true</code> if there are whitespace characters before the * cursor */ public boolean hasWhitespaceBeforeCursor() { TextSequence statementText = getStatementText(); // determine whether there are whitespaces before the cursor int statementLength = statementText.length(); int statementEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, statementLength); return statementLength != statementEnd; } /** * Returns whether there is a space character at offset position or not.<br> * <b>IMPORTANT</b>: note that while {@link #getNextChar()} and * {@link #getChar(int offset)} will return a space when cursor is at end of * document, this method will return false when cursor is at end of * document. * * @return <code>true</code> if there is a space character at offset * position, false otherwise or false when cursor is at end of * document */ public boolean hasSpaceAtPosition(int offset) { try { return offset >= 0 && offset < document.getLength() && document.getChar(offset) == ' '; } catch (BadLocationException e) { return false; } } /** * Returns completion requestor * * @return completion requestor (see {@link CompletionRequestor}) * @see #isValid(ISourceModule, int, CompletionRequestor) */ public CompletionRequestor getCompletionRequestor() { return requestor; } /** * Returns offset of the cursor position when code assist was invoked * * @return offset */ public int getOffset() { return offset; } /** * Returns previous word before the cursor position * * @throws BadLocationException */ public String getPreviousWord() throws BadLocationException { TextSequence statementText = getStatementText(); int statementLength = statementText.length(); int wordEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, statementLength); // read // whitespace int wordStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, wordEnd, true); if (wordStart < 0 || wordEnd < 0 || wordStart > wordEnd) { return ""; //$NON-NLS-1$ } String previousWord = statementText.subSequence(wordStart, wordEnd).toString(); if (hasWhitespaceBeforeCursor()) { return previousWord; } wordEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, wordStart - 1); // read // whitespace wordStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, wordEnd, true); if (wordStart < 0 || wordEnd < 0 || wordStart > wordEnd) { return ""; //$NON-NLS-1$ } previousWord = statementText.subSequence(wordStart, wordEnd).toString(); return previousWord; } /** * Returns previous word before the cursor position * * @throws BadLocationException */ public String getPreviousWord(int times) throws BadLocationException { TextSequence statementText = getStatementText(); int statementLength = statementText.length(); int wordEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, statementLength); // read // whitespace int wordStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, wordEnd, true); for (int i = 0; i < times - 1; i++) { statementLength = wordStart; wordEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, statementLength); // read // whitespace wordStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, wordEnd, true); } if (wordStart < 0 || wordEnd < 0 || wordStart > wordEnd) { return ""; //$NON-NLS-1$ } String previousWord = statementText.subSequence(wordStart, wordEnd).toString(); if (hasWhitespaceBeforeCursor()) { return previousWord; } wordEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, wordStart - 1); // read // whitespace wordStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, wordEnd, true); if (wordStart < 0 || wordEnd < 0 || wordStart > wordEnd) { return ""; //$NON-NLS-1$ } previousWord = statementText.subSequence(wordStart, wordEnd).toString(); return previousWord; } /** * Returns previous word before the cursor position * * @throws BadLocationException */ public int getPreviousWordOffset(int times) throws BadLocationException { TextSequence statementText = getStatementText(); int statementLength = statementText.length(); int wordEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, statementLength); // read // whitespace int wordStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, wordEnd, true); for (int i = 0; i < times - 1; i++) { statementLength = wordStart; wordEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, statementLength); // read // whitespace wordStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, wordEnd, true); } if (wordStart < 0 || wordEnd < 0 || wordStart > wordEnd) { return wordStart; } if (hasWhitespaceBeforeCursor()) { return wordStart; } wordEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, wordStart - 1); // read // whitespace wordStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, wordEnd, true); // if (wordStart < 0 || wordEnd < 0 || wordStart > wordEnd) { // return wordStart; // } return wordStart; } /** * Returns PHP token under offset * * @return PHP token * @throws BadLocationException */ public ITextRegion getPHPToken() throws BadLocationException { return getPHPToken(offset); } public ITextRegion getPHPToken(int offset) throws BadLocationException { return phpScriptRegion.getPHPToken(getOffset(offset, regionCollection, phpScriptRegion)); } private int getOffset(int offset, ITextRegionCollection regionCollection, IPHPScriptRegion phpScriptRegion) { int result = offset - regionCollection.getStartOffset() - phpScriptRegion.getStart() - 1; if (result < 0) { result = 0; } return result; } /** * Returns the word on which code assist was invoked * * @return prefix (will never be null) * @throws BadLocationException */ public String getPrefix() throws BadLocationException { return getPrefixWithoutProcessing(); } public String getPrefixWithoutProcessing() { if (hasWhitespaceBeforeCursor()) { return ""; //$NON-NLS-1$ } TextSequence statementText = getStatementText(); int statementLength = statementText.length(); int prefixEnd = PHPTextSequenceUtilities.readBackwardSpaces(statementText, statementLength); // read // whitespace int prefixStart = PHPTextSequenceUtilities.readIdentifierStartIndex(phpVersion, statementText, prefixEnd, true); return prefixStart < 0 ? "" : statementText.subSequence(prefixStart, prefixEnd).toString(); //$NON-NLS-1$ } /** * Returns the end of the word on which code assist was invoked * * @return * @throws BadLocationException */ public int getPrefixEnd() throws BadLocationException { ITextRegion phpToken = getPHPToken(); int endOffset = regionCollection.getStartOffset() + phpScriptRegion.getStart() + phpToken.getTextEnd(); if (PHPPartitionTypes.isPHPQuotesState(phpToken.getType())) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=475671 for (int index = offset; index < endOffset; index++) { char charAt = document.getChar(index); // Stop on quote (even in a heredoc section) or on whitespace: if (Character.isWhitespace(charAt) || charAt == '\'' || charAt == '"') { return index; } } } return endOffset; } /** * Returns next PHP token after offset * * @return PHP token * @throws BadLocationException */ public ITextRegion getNextPHPToken() throws BadLocationException { ITextRegion phpToken = getPHPToken(); do { phpToken = phpScriptRegion.getPHPToken(phpToken.getEnd()); if (!PHPPartitionTypes.isPHPCommentState(phpToken.getType()) && phpToken.getType() != PHPRegionTypes.WHITESPACE) { break; } } while (phpToken.getEnd() < phpScriptRegion.getLength()); return phpToken; } public ITextRegion getNextPHPToken(int times) throws BadLocationException { ITextRegion phpToken = null; int offset = this.offset; while (times-- > 0) { phpToken = getPHPToken(offset); do { phpToken = phpScriptRegion.getPHPToken(phpToken.getEnd()); if (!PHPPartitionTypes.isPHPCommentState(phpToken.getType()) && phpToken.getType() != PHPRegionTypes.WHITESPACE) { break; } } while (phpToken.getEnd() < phpScriptRegion.getLength()); if (phpToken == null) { return null; } else { offset = regionCollection.getStartOffset() + phpScriptRegion.getStart() + phpToken.getEnd(); } } return phpToken; } /** * Returns next word after the cursor position * * @throws BadLocationException */ public String getNextWord() throws BadLocationException { ITextRegion nextPHPToken = getNextPHPToken(); return document.get(regionCollection.getStartOffset() + phpScriptRegion.getStart() + nextPHPToken.getStart(), nextPHPToken.getTextLength()); } public String getNextWord(int times) throws BadLocationException { ITextRegion nextPHPToken = getNextPHPToken(times); return document.get(regionCollection.getStartOffset() + phpScriptRegion.getStart() + nextPHPToken.getStart(), nextPHPToken.getTextLength()); } /** * Returns next character after the cursor position (or ' ' if cursor * position is at end of document) * * @throws BadLocationException */ public char getNextChar() throws BadLocationException { return getChar(offset); } /** * Returns character at the given offset (or ' ' if offset is at end of * document) * * @throws BadLocationException */ public char getChar(int offset) throws BadLocationException { // if the location is the end of the document, we return ' ' to // avoid the BadLocationException if (document.getLength() == offset) { return ' '; } return document.getChar(offset); } public int getUseTraitStatementContext() { return getUseTraitStatementContext(offset, structuredDocumentRegion); } public int getUseTraitStatementContext(int offset, IStructuredDocumentRegion sdRegion) { List<String> types = new ArrayList<String>(); if (sdRegion == null) { sdRegion = structuredDocumentRegion; } int documentOffset = offset; if (documentOffset == sdRegion.getEndOffset()) { documentOffset -= 1; } ITextRegion tRegion = sdRegion.getRegionAtCharacterOffset(documentOffset); ITextRegionCollection container = sdRegion; if (tRegion instanceof ITextRegionContainer) { container = (ITextRegionContainer) tRegion; tRegion = container.getRegionAtCharacterOffset(offset); } if (tRegion != null && tRegion.getType() == PHPRegionContext.PHP_CLOSE) { tRegion = container.getRegionAtCharacterOffset(container.getStartOffset() + tRegion.getStart() - 1); } // This text region must be of type PhpScriptRegion: if (tRegion != null && tRegion.getType() == PHPRegionContext.PHP_CONTENT) { IPHPScriptRegion phpScriptRegion = (IPHPScriptRegion) tRegion; try { // Set default starting position to the beginning of the // PhpScriptRegion: int startOffset = container.getStartOffset() + phpScriptRegion.getStart(); // Now, search backwards for the statement start (in this // PhpScriptRegion): ITextRegion startTokenRegion; if (documentOffset == startOffset) { startTokenRegion = phpScriptRegion.getPHPToken(0); } else { startTokenRegion = phpScriptRegion.getPHPToken(offset - startOffset - 1); } // If statement start is at the beginning of the PHP script // region: while (true) { if (startTokenRegion.getStart() == 0) { return NONE; } if (!PHPPartitionTypes.isPHPCommentState(startTokenRegion.getType()) && startTokenRegion.getType() != PHPRegionTypes.WHITESPACE) { types.add(startTokenRegion.getType()); } if (startTokenRegion.getType() == PHPRegionTypes.PHP_CURLY_OPEN || startTokenRegion.getType() == PHPRegionTypes.PHP_INSTEADOF || startTokenRegion.getType() == PHPRegionTypes.PHP_SEMICOLON || startTokenRegion.getType() == PHPRegionTypes.PHP_AS) { break; } startTokenRegion = phpScriptRegion.getPHPToken(startTokenRegion.getStart() - 1); } } catch (BadLocationException e) { } } if (types.size() == 1) { String type = types.get(0); if (type == PHPRegionTypes.PHP_CURLY_OPEN || type == PHPRegionTypes.PHP_INSTEADOF || type == PHPRegionTypes.PHP_SEMICOLON) { return TRAIT_NAME; } else if (type == PHPRegionTypes.PHP_AS) { return TRAIT_KEYWORD; } if (type == PHPRegionTypes.PHP_INSTEADOF) { return TRAIT_KEYWORD; } } else if (types.size() == 2) { String type1 = types.get(0); String type = types.get(1); try { if (type == PHPRegionTypes.PHP_SEMICOLON && type1 == PHPRegionTypes.PHP_LABEL && Character.isWhitespace(document.getChar(offset - 1))) { return TRAIT_KEYWORD; } } catch (BadLocationException e) { } if (type == PHPRegionTypes.PHP_CURLY_OPEN || type == PHPRegionTypes.PHP_INSTEADOF || type == PHPRegionTypes.PHP_SEMICOLON || type1 == PHPRegionTypes.PHP_LABEL) { return TRAIT_NAME; } } else if (types.size() == 3) { String type = types.get(0); String type1 = types.get(1); String type2 = types.get(2); if (type == PHPRegionTypes.PHP_LABEL && type1 == PHPRegionTypes.PHP_LABEL && type2 == PHPRegionTypes.PHP_SEMICOLON) { return TRAIT_KEYWORD; } } else if (types.size() == 4) { String type = types.get(0); String type1 = types.get(1); String type2 = types.get(2); if (type == PHPRegionTypes.PHP_LABEL && type1 == PHPRegionTypes.PHP_PAAMAYIM_NEKUDOTAYIM && type2 == PHPRegionTypes.PHP_LABEL) { return TRAIT_KEYWORD; } } return NONE; } public boolean isInUseTraitStatement() { return isInUseTraitStatement(offset, structuredDocumentRegion); } private List<String> useTypes; public boolean isInUseTraitStatement(int offset, IStructuredDocumentRegion sdRegion) { PHPVersion phpVersion = ProjectOptions.getPHPVersion(sourceModule.getScriptProject().getProject()); if (phpVersion.isLessThan(PHPVersion.PHP5_4)) { return false; } if (useTypes != null) { return true; } if (sdRegion == null) { sdRegion = structuredDocumentRegion; } int documentOffset = offset; if (documentOffset == sdRegion.getEndOffset()) { documentOffset -= 1; } ITextRegion tRegion = sdRegion.getRegionAtCharacterOffset(documentOffset); ITextRegionCollection container = sdRegion; if (tRegion instanceof ITextRegionContainer) { container = (ITextRegionContainer) tRegion; tRegion = container.getRegionAtCharacterOffset(offset); } if (tRegion != null && tRegion.getType() == PHPRegionContext.PHP_CLOSE) { tRegion = container.getRegionAtCharacterOffset(container.getStartOffset() + tRegion.getStart() - 1); } // This text region must be of type PhpScriptRegion: if (tRegion != null && tRegion.getType() == PHPRegionContext.PHP_CONTENT) { IPHPScriptRegion phpScriptRegion = (IPHPScriptRegion) tRegion; try { // Set default starting position to the beginning of the // PhpScriptRegion: int startOffset = container.getStartOffset() + phpScriptRegion.getStart(); // Now, search backwards for the statement start (in this // PhpScriptRegion): ITextRegion startTokenRegion; if (documentOffset == startOffset) { startTokenRegion = phpScriptRegion.getPHPToken(0); } else { startTokenRegion = phpScriptRegion.getPHPToken(offset - startOffset - 1); } // If statement start is at the beginning of the PHP script // region: while (true) { if (startTokenRegion.getStart() == 0) { return false; } if (startTokenRegion.getType() == PHPRegionTypes.PHP_CURLY_OPEN) { // Calculate starting position of the statement (it // should go right after this startTokenRegion): // startOffset += startTokenRegion.getEnd(); TextSequence statementText1 = getStatementText(startOffset + startTokenRegion.getStart() - 1); startTokenRegion = phpScriptRegion .getPHPToken(startTokenRegion.getStart() - statementText1.length()); if (startTokenRegion.getType() == PHPRegionTypes.PHP_USE) { String[] types = statementText1.toString().trim().substring(3).trim().split(","); //$NON-NLS-1$ useTypes = new ArrayList<String>(); for (String type : types) { useTypes.add(type.trim()); } return true; } else { return false; } } else if (startTokenRegion.getType() == PHPRegionTypes.PHP_CURLY_CLOSE) { return false; } startTokenRegion = phpScriptRegion.getPHPToken(startTokenRegion.getStart() - 1); } } catch (BadLocationException e) { } } return false; } /** * This method get enclosing type element. It completely ignore statements * without { */ protected IModelElement getEnclosingElement() { try { int offset = this.offset; PHPHeuristicScanner heuristicScanner = PHPHeuristicScanner.createHeuristicScanner(document, offset, true); if (offset >= document.getLength()) { offset = document.getLength() - 1; } int open = heuristicScanner.findOpeningPeer(offset, PHPHeuristicScanner.UNBOUND, PHPHeuristicScanner.LBRACE, PHPHeuristicScanner.RBRACE); if (open > -1) { int close = heuristicScanner.findOpeningPeer(offset, PHPHeuristicScanner.UNBOUND, PHPHeuristicScanner.RBRACE, PHPHeuristicScanner.LBRACE); if (close > open && open == heuristicScanner.findOpeningPeer(close - 1, PHPHeuristicScanner.UNBOUND, PHPHeuristicScanner.LBRACE, PHPHeuristicScanner.RBRACE)) { open = heuristicScanner.findOpeningPeer(open - 1, PHPHeuristicScanner.UNBOUND, PHPHeuristicScanner.LBRACE, PHPHeuristicScanner.RBRACE); } } TextSequence statementText = getStatementText(); int statementStart = statementText.length() > 0 ? statementText.getOriginalOffset(0) + 1 : -1; if (open < 0 && statementStart < 0) { return sourceModule.getElementAt(offset); } IModelElement elementAt = sourceModule.getElementAt(open); IModelElement elementAt2 = sourceModule.getElementAt(statementStart); if (elementAt == null && elementAt2 == null) { return sourceModule.getElementAt(offset); } if (elementAt instanceof ISourceReference && elementAt2 instanceof ISourceReference) { if (((ISourceReference) elementAt).getSourceRange().getOffset() > ((ISourceReference) elementAt2) .getSourceRange().getOffset()) { return elementAt; } else { return elementAt2; } } else if (elementAt != null) { return elementAt; } return elementAt2; } catch (BadLocationException e) { Logger.logException(e); } catch (ModelException e) { Logger.logException(e); } return null; } protected IStructuredDocumentRegion getStructuredDocumentRegion() { return structuredDocumentRegion; } public List<String> getUseTypes() { return useTypes; } }