1) Fixed issue #764: Ignore strings when looking for single line comments.
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpdt / internal / ui / text / PHPCodeReader.java
index fffffda..96d65c8 100644 (file)
@@ -20,22 +20,15 @@ public class PHPCodeReader extends SingleCharReader {
 
        /** The EOF character */
        public static final int EOF = -1;
-
        private boolean fSkipComments = false;
-
-       private boolean fSkipStrings = false;
-
-       private boolean fForward = false;
-
+       private boolean fSkipStrings  = false;
+       private boolean fForward      = false;
+       
        private IDocument fDocument;
-
-       private int fOffset;
-
-       private int fEnd = -1;
-
-       private int fCachedLineNumber = -1;
-
-       private int fCachedLineOffset = -1;
+       
+       private int fOffset;                           // The current text position within the editor's text
+       private int fEnd              = -1;
+       private int fCachedLineNumber = -1;            // Holds the last line we checked for single line comments
 
        public PHPCodeReader() {
        }
@@ -93,76 +86,91 @@ public class PHPCodeReader extends SingleCharReader {
                }
        }
 
-       private void gotoCommentEnd() throws BadLocationException {
-               while (fOffset < fEnd) {
-                       char current = fDocument.getChar(fOffset++);
+       private int gotoCommentEnd (int nTextPos) throws BadLocationException {
+               while (nTextPos < fEnd) {
+                       char current = fDocument.getChar (nTextPos++);
+                       
                        if (current == '*') {
-                               if (fOffset < fEnd && fDocument.getChar(fOffset) == '/') {
-                                       ++fOffset;
-                                       return;
+                               if ((nTextPos < fEnd) && 
+                                   (fDocument.getChar (nTextPos) == '/')) {
+                                       ++nTextPos;
+                                       
+                                       return nTextPos;
                                }
                        }
                }
+               
+               return nTextPos;
        }
 
-       private void gotoStringEnd(char delimiter) throws BadLocationException {
-               while (fOffset < fEnd) {
-                       char current = fDocument.getChar(fOffset++);
-                       if (current == '\\') {
-                               // ignore escaped characters
-                               ++fOffset;
-                       } else if (current == delimiter) {
-                               return;
+       /**
+        * 
+        * @param delimiter
+        * @throws BadLocationException
+        */
+       private int gotoStringEnd (int nTextPos, char delimiter) throws BadLocationException {
+               while (nTextPos < fEnd) {               // If long as we are not at the end of text
+                       char current = fDocument.getChar (nTextPos++);
+                       
+                       if (current == '\\') {                          // ignore escaped characters
+                               ++nTextPos;
+                       } 
+                       else if (current == delimiter) {
+                               return nTextPos;
                        }
                }
+               
+               return nTextPos;                        // End position
        }
 
-       private void gotoLineEnd() throws BadLocationException {
-               int line = fDocument.getLineOfOffset(fOffset);
-               fOffset = fDocument.getLineOffset(line + 1);
+       /**
+        * 
+        * @param nTextPos               The current text position
+        * 
+        * @return                       The position of the start of next line
+        * 
+        * @throws BadLocationException
+        */
+       private int gotoLineEnd (int nTextPos) throws BadLocationException {
+               int line = fDocument.getLineOfOffset (nTextPos); // Get the line number of the current text position
+               
+               return fDocument.getLineOffset (line + 1);
        }
 
-       private int readForwards() throws BadLocationException {
+       private int readForwards () throws BadLocationException {
                while (fOffset < fEnd) {
                        char current = fDocument.getChar(fOffset++);
 
                        switch (current) {
-                       case '"':
-                       case '\'':
-
-                               if (fSkipStrings) {
-                                       gotoStringEnd(current);
-                                       continue;
-                               }
-
-                               return current;
-                       case '#':
-
-                               if (fSkipComments && fOffset < fEnd) {
-                                       gotoLineEnd();
-                                       continue;
-                               }
-
-                               return current;
-
-                       case '/':
-
-                               if (fSkipComments && fOffset < fEnd) {
-                                       char next = fDocument.getChar(fOffset);
-                                       if (next == '*') {
-                                               // a comment starts, advance to the comment end
-                                               ++fOffset;
-                                               gotoCommentEnd();
-                                               continue;
-                                       } else if (next == '/') {
-                                               // '//'-comment starts, advance to the line end
-                                               gotoLineEnd();
-                                               continue;
-                                       }
-                               }
-
-                               return current;
-
+                           case '"':
+                           case '\'':
+                               if (fSkipStrings) {
+                                   fOffset = gotoStringEnd (fOffset, current);
+                                   continue;
+                               }
+                               return current;
+                               
+                           case '#':
+                               if (fSkipComments && fOffset < fEnd) {
+                                   fOffset = gotoLineEnd (fOffset);
+                                   continue;
+                               }
+                               return current;
+
+                           case '/':
+                               if (fSkipComments && fOffset < fEnd) {
+                                   char next = fDocument.getChar(fOffset);
+                                   
+                                   if (next == '*') {                                  // A comment starts, advance to the comment end
+                                       ++fOffset;
+                                       fOffset = gotoCommentEnd (fOffset);
+                                       continue;
+                                   } else if (next == '/') {                   // '//'-comment starts, advance to the line end
+                                       fOffset = gotoLineEnd (fOffset);
+                                       continue;
+                                   }
+                               }    
+                               return current;
                        }
 
                        return current;
@@ -171,86 +179,152 @@ public class PHPCodeReader extends SingleCharReader {
                return EOF;
        }
 
-       private void handleSingleLineComment() throws BadLocationException {
-               int line = fDocument.getLineOfOffset(fOffset);
-               if (line < fCachedLineNumber) {
-                       fCachedLineNumber = line;
-                       fCachedLineOffset = fDocument.getLineOffset(line);
-                       int offset = fOffset;
-                       while (fCachedLineOffset < offset) {
-                               char current = fDocument.getChar(offset--);
-
-                               if (current == '/' && fCachedLineOffset <= offset
-                                               && fDocument.getChar(offset) == '/') {
-                                       fOffset = offset;
-                                       return;
-                               }
-
-                               if (current == '#' && fCachedLineOffset <= offset) {
-                                       fOffset = offset;
-                                       return;
+       /**
+        * Check whether the current line contains a single line comment.
+        * If it contains a single line comment (// or #), than set fOffset (the global character index)
+        * to the character just before the single line comment.
+        * 
+        * @throws BadLocationException
+        */
+       
+       private void handleSingleLineComment () throws BadLocationException {
+           char current;
+               int  line = fDocument.getLineOfOffset (fOffset);         // Get the line number which belongs to the current text position fOffset
+               
+               if (line < fCachedLineNumber) {                          // If we didn't parse this line already
+                       fCachedLineNumber = line;                            // Remember this line for the next time (so we don't search again!)   
+                       int nOffset       = fDocument.getLineOffset (line);  // Get the start position of current line      
+                       
+                       while (nOffset < fOffset) {                          // As long as the text position is within the current line 
+                               current = fDocument.getChar (nOffset);           // Get the character from the current text position
+
+                               switch (current) {
+                                   case '/':
+                                       if (fDocument.getChar (nOffset + 1) == '/') { // If the following character is '/'
+                                           fOffset = nOffset - 1;
+                                           
+                                           return;
+                                       }
+                                       break;    
+                                   
+                                   case '#':
+                        fOffset = nOffset - 1;
+                        return;
+                                   
+                                   case '"':                                           // It's a string start quote
+                                   case '\'':
+                                       nOffset++;                                      // Set to next character
+                                       
+                                       while (nOffset < fOffset) {                     // As long as we are within the same line
+                                           char cChar = fDocument.getChar (nOffset++);
+                                           
+                                           if (cChar == '\\') {                        // Ignore escaped characters
+                                               ++nOffset;
+                                           } 
+                                           else if (cChar == current) {                // If end of string found 
+                                               break;
+                                           }
+                                       }
+                                       break;
                                }
+                               
+                               nOffset++;                                              // Go for the next character
                        }
                }
        }
 
-       private void gotoCommentStart() throws BadLocationException {
-               while (0 < fOffset) {
-                       char current = fDocument.getChar(fOffset--);
-                       if (current == '*' && 0 <= fOffset
-                                       && fDocument.getChar(fOffset) == '/')
-                               return;
+       /**
+        * We search the for the block comment start sequence "/*"
+        * 
+        * The returned value points to the '/'
+        * 
+        * @throws BadLocationException
+        * 
+        * @return The new text position
+        */
+       
+       private int gotoCommentStart (int nTextPos) throws BadLocationException {
+               while (0 < nTextPos) {                                // As long as we are not at the start of the editor text
+                   char current = fDocument.getChar (nTextPos--);    // Get the character from the current text position        
+                       
+                       if ((current == '*') &&                           // If current character is a '*' 
+                           (0 <= nTextPos) &&                            // and if we are not yet at the start of the editor text 
+                           (fDocument.getChar (nTextPos) == '/')) {      // and the previous character is a '/', 
+                               return nTextPos;                              // We found the block comment start "/*"
+                       }
                }
+               
+               return nTextPos;
        }
 
-       private void gotoStringStart(char delimiter) throws BadLocationException {
-               while (0 < fOffset) {
-                       char current = fDocument.getChar(fOffset);
-                       if (current == delimiter) {
-                               if (!(0 <= fOffset && fDocument.getChar(fOffset - 1) == '\\'))
-                                       return;
+       /**
+        * The string closing quote has been found, when reading the editor text backwards.
+        * So we have to search for the start of the string
+        * 
+        * The returned value points to '"' or '''
+        * 
+        * @param delimiter The string double quote '"' or single ''' quote we search for
+        * 
+        * @throws BadLocationException
+        */
+       private int gotoStringStart (int nTextPos, char delimiter) throws BadLocationException {
+               while (0 < nTextPos) {                              // As long as we are not at the start of the editor text
+                       char current = fDocument.getChar (nTextPos);    // Get the character from the current text position 
+                                                                       
+                       if (current == delimiter) {                     // If we found the same character ('"' or ''') again, we have found the string start
+                               if (!(0 <= nTextPos &&                        
+                                     fDocument.getChar (nTextPos - 1) == '\\')) // If the character before the string quote is not an '/' 
+                               return nTextPos;                                 // we found the string start
                        }
-                       --fOffset;
+                                                                           
+                       --nTextPos;                                          // Go one character back
                }
+               
+               return nTextPos;
        }
 
+       /**
+        * Read the editor text backwards
+        * 
+        */
+       
        private int readBackwards() throws BadLocationException {
-
-               while (0 < fOffset) {
-                       --fOffset;
-
-                       handleSingleLineComment();
-
-                       char current = fDocument.getChar(fOffset);
-                       switch (current) {
-                       case '/':
-
-                               if (fSkipComments && fOffset > 1) {
-                                       char next = fDocument.getChar(fOffset - 1);
-                                       if (next == '*') {
-                                               // a comment ends, advance to the comment start
-                                               fOffset -= 2;
-                                               gotoCommentStart();
-                                               continue;
-                                       }
-                               }
-
-                               return current;
-                       case '"':
-                       case '\'':
-
-                               if (fSkipStrings) {
-                                       --fOffset;
-                                       gotoStringStart(current);
-                                       continue;
-                               }
-
-                               return current;
+           char current;                                                // The character on position fOffset
+           
+               while (0 < fOffset) {                                        // As long as we are not at the beginning of the editor text
+                       --fOffset;                                               // Step back one character
+
+                       handleSingleLineComment ();                              // Search for a single line comment within the current line
+                                                                                // If there is a single line comment, fOffset is set to position just before the single line comment
+
+                       current = fDocument.getChar (fOffset);                   // Read the current character
+                       switch (current) {                                       // Process the current character
+                           case '/':                                            // Is it a single line comment? 
+                               if (fSkipComments &&                             // When comments should be skipped when parsing
+                                   fOffset > 1) {                               // and if there is indeed an additional character before that '/'
+                                   char prev = fDocument.getChar (fOffset - 1); // Look at the character in front of the '/'
+                                   
+                                   if (prev == '*') {                           // If '*' than a block comment ends here, advance to the comment start
+                                       fOffset -= 2;                            // Set character pointer to character before "*/"
+                                       fOffset  = gotoCommentStart (fOffset);   // and search for the starting "/*" of the block comment
+                                       continue;
+                                   }
+                               }
+                               return current;                                  // No block comment end, so return the current character
+                               
+                           case '"':                                            // Is it a string double quote closing '"'?                                                
+                           case '\'':                                           // or a string single quote closing '''?
+                               if (fSkipStrings) {                              // If we should skip strings when parsing
+                                   --fOffset;                                   // Set pointer one before the string closing quote 
+                                   fOffset = gotoStringStart (fOffset, current);// and search the start of string ('"' or ''')
+                                   continue;
+                               }
+                               return current;                                  // No string skip, so return the current character
                        }
 
-                       return current;
+                       return current;                                          // No string and no comment
                }
 
-               return EOF;
+               return EOF;                                                  // When the start of the text has been found
        }
 }