1 ZICDOC introduction
1.1 What is ZICDOC generator
ZICDOC is an ABAP program, which ties to analyze source code of other ABAP program and create then HTML documentation. It is based mainly on comments extracted from source code, but it also recognize a few simple objects like database tables, forms, classes and similar code blocks and tries to assign comments to these objects. As a result, you can receive HTML file describing analyzed program. The level of details depend on what programmer "left" in source code.
1.2 Short story
Documenting source code of any program is crucial for it's later maintenance and extending. There are many tools for storing documentation (from word processors and file systems to advanced and sophisticated databases with version management, workflows and other wonderful functionalities). But programmers don't like to use them. After several program's modification, such a documentation is typically outdated and sooner or later - useless. I see, that the only place where programmers eventually leave additional information is source code (comments).
Suppose, that you have wonderful, detailed and up-to-date information inside source code of your program. That's great, but it isn't the end of you problems. You probably write a program not for yourself. Very soon your manager, quality controller or customer will ask you for any kind of documentation of your work...
It would be nice to have any tool which will automatically create such a documentation based on information in source code. There are several such a tools on the market - JAVADOC is good example, which solves problem of Java programmers. Unfortunately, I have not found such a generator for ABAP (I mean freeware, I heard some time ago about similar tool for ABAP, but it was very expensive).
I have been thinking about automatic documentation generator for several months, but I have had no motivation do it. I have started programming it, but never finished. About one year ago, I have decided finally to go into object-oriented ABAP (learn it) and it was turning point. I was looking for any real task for implementing (not just simple report displaying data from several tables) and I reminded about the generator.
After a few weeks, I had a class analyzing source code and storing results in internal tables. The next step was preparing any solution for displaying these results. At the beginning, I considered creation of XML files and then preparing XML transformations for converting XML data into more readable HTML, PDF or any other format. But, when I looked into details of XMLT - I gave up. It is so complex like new programming language. Finally, I did not decide to learn XML, XMLT and HTML, but just only HTML (it was also new for me). I only introduced CSS (cascade style sheets) to be more flexible with formatting output information.
Now, if you know that the ZICDOC project was for me the first contact with object-oriented ABAP, HTML and CSS, I hope that you will be more patient reading source code of the generator. It still needs some improvements or corrections, but at he moment I have no time to do it.
1.4 SAP R/3 versions
Program was tested mainly on WAS 6.40 and WAS 7.0, but it should work on all versions of WAS. It was also tested a little on 4.6C (I started on this version), but It offers oldest version of statement SCAN ABAP-SOURCE. It has different syntax and results. Source code of the generator contains part described with word COMPATYBILITY (for 4.6C), so it is probably possible to adjust program to that version.
2 Using ZICDOC
2.1 Installation
ATTENTION!
Due to size limit of single Weblog, I had to put source code of programs in part II, III and IV of the blog.
I tried not to use any nonstandard dictionary objects. You can even find, that I haven't used program text for HTML tags, but created them as constants. So, it should be enough just to create all ABAP programs and then activate them. If you want to understand what fields are on selection screen of the main program, copy texts from source code (they are at the beginning ) to selection texts.
Additionally, you have to create file ZIcDocStyle.css.
You should create the following programs:
ZICDOC - the main program (type ‘1') of the generator. It is ready-to-use program or just example how to call generator from other programs.
ZICDOC_CL_HTML - include (type ‘I') with class supporting creation of HTML file
ZICDOC_CL_CODE_ANALYSIS - include containing class for source code analysis
ZICDOC_CL_CODE_ANALYSIS_HTML - include with class analyzing code and creating HTML documentation
1.1 Starting generator
The main program of generator is ZICDOC. Selection screen is below:
It allows entering the path to generated output HTML file.
As a input you have two options:
Enter a name of the program in the system (it is suggested). You can try with ZICDOC itself, so you will have documentation of the generator.
Enter a name and path of file on local disk with source code to be analyzed. This option limits analysis to this single file - any INCLUDES are not taken into account.
Additionally, you can influence the content of generated file (see also section 4). The meaning of options is the following:
INCLUDES - hierarchy - generates section with a list of includes of the main analyzed program. See: 4.1.
INCLUDES - details - generates section with information about each include (name, comments, list of code units). See: 4.3.
Database tables - generates section with a list of database tables accessed from the analyzed program. See: 4.2.
Class components - generates section with details and components of classes and interfaces. See: 4.4.
Non-class code units - generates section with list of list events, form, function modules and other code units. See: 4.5.
Code units hierarchy - generates section with hierarchy of class (for instance one for from another). See: 4.6.
Protected class components - if protected components have to be placed in output file (in addition do public).
Private class components - if private components have to be placed in output file (in addition do public).
Comments include HTML tags - if selected, comments are written to HTML file without any conversion. It allows using formatting tags inside comments (like <br>), but characters like &, <, > can disappear in output file. If you not select this check box, comments are converted to HTML text. Characters like &, <, > are outputted correctly (converted to special strings), but you cannot use HTML tags in your comments.
After starting program, and waiting several seconds, you will (hopefully) see message, that NNNN bytes transferred. It means that your program has been analyzed and you can see results.
Attention!
To see correctly HTML file, you must place in the same folder file with styles: ZIcDocStyle.css. You can find additional information in section 2.6).
1.2 Prerequisites
Before you can create with ZICDOC documentation for any program, the analyzed source code:
Should be activated (at least syntax check performed). Behavior of the generator during analyzing of code with syntax errors is undefined.
It is suggested to verify comments in the analyzed code and, if possible, adjust it to standards described in this documents.
1.3 Basic functionality
The generator tries to find comments I source code and assign them to code units (like programs, forms, classes, etc). This information is later used to create documentation for these units. Program recognizes the following types of statements:
Comments - specials rules apply (see section 3)
List events - like: START-OF-SELECTION, END-OF-SELECTION, INITIALIZATION, GET, AT.
Database operation statements - like: TABLES, SELECT, UPDATE, INSERT, MODIFY, DELETE. Based on them, list of tables used in the program can be built. It doses not cover operation performed in function modules called from the program (they are not analyzed).
Class and interface definition. List of components are built.
Form definition and call - like FORM, PERFORM
Report calls - like SUBMIT
Function module definition - like FUNCTION. The program has not been test for function groups, so it can require improvements.
Method definition - like METHOD
Function and methods calls - like CALL xxx (FUNCTION, CUSTOMER-FUNCTION, BADI, METHOD, TRANSACTION).
1.4 Technical description of ZICDOC
I tried to write documentation of the ZICDOC in the source code. Try to generate HTML file for the program (it can be the first exercise). Additional information you will find directly in source code.
In general, the generator is based on built-in keyword SCAN ABAP-CODE (see online help for ABAP). It performs decomposition of source code into single statements and tokens. They can be later analyzed by your own program.
1.5 Cascade Style Sheets
Generation of output HTML file is based on CSS. It allows using simple HTML tags in generated document and storing formatting information in separate file. You can, for instance, have several CSS files with different formatting, and depending on which one is used, different result will be displayed. You can experiment with CSS file and change different options. You can receive quite interesting results.
The name of CSS file is inside HTML file (in the header). The name of file is ZIcDocStyle.css and it must be located in the same directory as the main HTML file. Of course, you can edit HTML file and easy change the name of used CSS file.
1.5.1 CSS for beginners
CSS files can be edit with dedicated editors (which show you formatting options in dialog windows) or just any plain text editor (like Notepad). In the file, you can assign formatting options (like font name and size, color, table cell width) to specific HTML tags. For instance, headers are displayed with style H1 (in HTML document: <h1>Header text</h1>). In CSS file we define, that this style uses sans-serif font, size of 160% of default, bold and wit additional space before and after. Important thing - if you don't define a specific parameter - it is derived from parent node. It is a little complicated to explain here, but there are many free HTML and CSS courses on WEB.
I have used three basic forms of defining styles (it was an exercise for me):
Define style for single tags - like for <h1> to <h6>, <body>, <dfn> and others
Define style for nested tags - used for pair <td><samp>. If tag <samp> is nested inside <td> (inside tables cell) then width of a cell must be equal 25ex. By nesting, I understand: <td><samp>Any text in cell</samp></td>
Define class for tag - used for TD.dbname. This style is used when in HTML document you use <td class="dbname">Text</td>.
2 Comments
Generated documentation is based mainly on comments entered by programmer. This section describes rules, which should be considered.
2.1.1 General rules
Source code comments are very important for understanding usage of functions, forms, objects and individual lines of code. Therefore, program reads comments and places them in output file as description of specific objects.
Depending on a context, comments can describe code before or after it. To assign comments to right objects, strict rules must be applied by a programmer. The most important are described below.
All following lines of comments are treated as continuous string and are concatenated into one paragraph (section, segment). New paragraph starts when:
- Blank line is between lines of comment (without even *)
- After any code statement
Program assigns single paragraph to specific objects. It means, that if we have several paragraphs (separated by blank lines), only the first or the last will be used. If you want to use blank lines as visual separators inside comments, enter single * at the beginning of the blank line.
All comments beginning with " (quotation marks) not in the first column are ignored.
All comments, which has 3 the same character starting on 4-th column are ignored (all comments separating parts of code are ignored). Example: *& ---------
Program recognizes special comments types. They are cognized by beginning characters of the first line of comment paragraph (details below):
*& - comment on program level
*" - comment inside function or other type of coding block (form, method, class)
* or " - other comment
Comments describing programs and includes should start with characters: *& (asterix + ampersand). They are treated in special way - the first appearance of such a comment is assigned to program (include). All others (following) are treated in normal way (like comment before the next statement). As a result, program's description can be placed at the end of the program (if there is no other above, like generated by Pretty Printer for forms.) See additional description below.
All comments inside implementation of forms, methods and similar coding blocks are ignored, except starting with two characters: *". They can be placed inside block, but refer not to the following statement, but block as general (see point 3.1.4).
There should be at least one blank line after program comments and the following comments (for instance assigned to form or program event).
It is possible to place special predefined tags (variables) at the beginning of comment. They start with @ (at). The list of predefined tags is below. Tags starts different parts of comment and can be used to generate a special output format (for instance use different colors or font for each comment's part).
Comments can include HTML formatting tags. The typical is <br> for line break. If you need then to write characters: <, >, &, | or ~, you need to enter:
< <
> >
& &
| ¦
~ ˜
It is controlled by parameter on selection screen of the ZICDOC program.
2.1.2 Special tags in comments
Comments can contain variables (tags) starting with character @. They can be any single word. There are several predefined (assumed to be used) but other are treated in the same way - a special formatting cab be applied in output file.
List of examples:
@Info - description of the object. It is default tag for comment, so it is assigned also if no tag has been written at the beginning of the comment. The word Info is not outputted to HTML file.
@Author - author of the code
@Date - date of creation
@Change - change details
The following tags are treated in different way. The generator use the word following the tag as its special parameter (like in: * @Param I_MATNR Material number). Parameters can be issued with different formatting options (font). Only the following predefined variables can have parametrs (it is hard-coded):
@Param - parameter of form, method
@Using - parameter of form
@Change, @Changing - parameter of form
@Import, @Importing - import parameter
@Export, @Exporting - export parameter
@Return, @Returning - return parameter
@Receiving - parameter of method
@Tables - table parameter
@Throws, @Exception, @Raising - exception generated by code
2.1.3 Program comments
At the beginning of each main program or include it is possible to write comment describing this unit. This comment is recognized by beginning characters: *&. It is not required, that all lines of this part begins with these 2 characters. It is enough, that the first line begins with them. All following lines can begin with single character *.
Program comment can start in any line of code, even at the end of program. I suggest to enter it at the beginning, because Pretty Printer generates form's header comments beginning wit *&, so it can lead to unexpected results. Program comment ends with the firs blank line or statement (just no-comment). Example:
Code:
*&---------------------------------------------------------------------*
*& Report ZICDOC_TEST1
*&
*&---------------------------------------------------------------------*
*& @Author Ireneusz Cwir
*& @Date 18.01.2008
*& @Info Program for testing documentation generation by ZICDOC
*&---------------------------------------------------------------------*
* This comment, although doesn't begin with '*&' belong to program's
* description part. It is because there is no empty line between
* above section and this section.<br> It will start in new line -
* thanks to HTML tag: <br>
* Line with horizontal separator is ignored.
*
* This comment also belongs to above section, because line above
* starts with '*', so it is no really blank line.
* This doesn't belong to previous section, because there is really
* empty line above.
2.1.4 Code units comments
Comments for forms, list events and other similar code units are placed before the unit. The last continuous section of comment (without blank line) before unit is assigned to that unit.
Comments can contain special tags using for marking special sections of comments (like author, date, parameters - see point 3.1.2).
If you want to output comment from inside form or method, you must use comment starting with*".
3 Output file sections
Output HTML file can contain different sections. Selection screen parameters control this. Sections are describe below.
3.1 Hierarchy of programs and includes
Section lists all includes used in the program. They are printed as subnodes of the analyzed program. This section contains also macros called from the program. If source code of include has been available for analysis and detailed section should be generated, nodes are created as links to detailed descriptions of each include.
3.2 Database tables
Section lists database tables used in the program (covers includes). The following information is displayed for each table:
Table name
Access mode:
T - declaration with TABLES statement
S - select
U - update
I - insert
M - modify (update or insert)
D - delete
Table title - from dictionary
3.3 Programs and includes summary
This section contains the following information for each program (include):
Program name
Program title - from attributes screen of a program
Program description - from program comments (see point 3.1.3)
List of events, forms and other code units defined in the program (include)
3.4 Class components
Section contains more detailed information about classes defined and implemented in analyzed program:
Class name and its declaration
Base class
Attributes and methods with comments - based on class definition. Comments are displayed also from method implementation.
3.5 Non-class code units
Section contains more detailed information about code units in each program (include):
Type of code unit (list event, form, function)
Name of the unit
Parameters of the unit
Database tables affected by the unit (with access mode: reads, updates - see point 4.2)
Unit description - comments before unit code
3.6 Code units calls hierarchy
The section contains hierarchy of calls of forms, function modules and other code units. It is intended for documenting reports. Then, list events are roots of calls. Other program types have not been tested. For instance, it does not list calls made from class methods.
ZICDOC does not recognize methods calls if short version are used.
Cwir Ireneusz is internal R/3 support team member in Cadbury Wedel.
Last edited by admin on Fri Nov 28, 2008 2:15 am; edited 2 times in total
This post is the second part of WeBlog describing ZICDOC - generator of HTML description of ABAP program.
I tried not to use any nonstandard dictionary objects. You can even find, that I haven't used program text for HTML tags, but created them as constants. So, it should be enough just to create all ABAP programs and then activate them. If you want to understand what fields are on selection screen of the main program, copy texts from source code (they are at the beginning ) to selection texts.
Additionally, you have to create local file ZIcDocStyle.css and paste into it content from the field below:
Code:
<!-- Default font for the document -->
BODY {
font-family: "Verdana", "Arial", "Helvetica", "sans-serif";
font-size: x-small;
}
You should create the following programs:
ZICDOC - the main program (type ‘1') of the generator. It is ready-to-use program or just example how to call generator from other programs.
ZICDOC_CL_HTML - include (type ‘I') with class supporting creation of HTML file
ZICDOC_CL_CODE_ANALYSIS - include containing class for source code analysis
ZICDOC_CL_CODE_ANALYSIS_HTML - include with class analyzing code and creating HTML documentation
Code:
*&---------------------------------------------------------------------*
*& Report ZICDOC
*&
*&---------------------------------------------------------------------*
* @Author Ireneusz Cwir
* The main program of ZICDOC generator. It shows also how to call
* program analysis and HTML file generation from other code.
REPORT zicdoc LINE-SIZE 256.
* These texts are defined in properties of the program.
* You can uncomment them (optionally) and copy to right fields.
*
* Title (Goto -> Attributes)
* ZICDOC - ABAP documentation generator
*
* Selection parametrs (Goto -> Text elements -> Selection texts):
*P_CCPRIV Private class components
*P_CCPROT Protected class components
*P_CLSCMP Class components
*P_FHTML Output file name (html)
*P_FSRC Cource code file name
*P_HTMLCM Comments include HTML tags
*P_INCDET INCLUDES - details
*P_INCHIE INCLUDES - hierarchy
*P_PROG Analysed program name
*P_TABLES Database tables
*P_UNTDET Code units - details
*P_UNTHIE Code units - hierarchy
PARAMETERS: p_prog LIKE trdir-name DEFAULT 'ZICDOC_TEST1',
p_fsrc LIKE rlgrap-filename DEFAULT 'd:\Z22IC002.txt'.
SELECTION-SCREEN SKIP 1.
PARAMETERS: p_fhtml LIKE rlgrap-filename DEFAULT 'D:\ZICDOC_TEST1.html'.
SELECTION-SCREEN SKIP 1.
PARAMETERS: p_inchie AS CHECKBOX DEFAULT 'X',
p_incdet AS CHECKBOX DEFAULT 'X',
p_clscmp AS CHECKBOX DEFAULT 'X',
p_unthie AS CHECKBOX DEFAULT 'X',
p_untdet AS CHECKBOX DEFAULT 'X',
p_tables AS CHECKBOX DEFAULT 'X'.
SELECTION-SCREEN SKIP 1.
PARAMETERS: p_ccprot AS CHECKBOX DEFAULT 'X',
p_ccpriv AS CHECKBOX DEFAULT 'X'.
SELECTION-SCREEN SKIP 1.
PARAMETERS: p_htmlcm AS CHECKBOX DEFAULT 'X'.
* Include classe for code analysis and HTML file generation
INCLUDE zicdoc_cl_code_analysis_html.
*----------------------------------------------------------------------
* Reference to the main objectof analysis.
DATA: ref_html TYPE REF TO zcl_ic_code_analysis_html.
* Additional data
DATA: gv_str TYPE string.
DATA: gv_retcode TYPE i.
* Create object for code analysis
CREATE OBJECT ref_html.
* Depending on parameters entered on selection screen, call method for
* anlysing code of program in the system or code uploaded
* from local file (from presentation server or PC).
IF p_prog IS NOT INITIAL.
* Helper function for displaying tables with results of code scanning.
* Uncomment them if you are interested in further development of ZICDOC
* and you want to understand details of the code analysis.
* CALL METHOD ref_html->dump_statements.
* CALL METHOD ref_html->dump_statements_detailed.
* CALL METHOD ref_html->dump_tables_scan.
*&---------------------------------------------------------------------*
*& Include ZICDOC_CL_HTML
*&---------------------------------------------------------------------*
* Contains helper methods for creating HTML file.
CLASS zcl_ic_html DEFINITION.
PUBLIC SECTION.
* Table with content of HTML document (source text of document).
DATA: gt_content TYPE STANDARD TABLE OF string.
METHODS: constructor.
METHODS: reset.
* Returns string afetr conversion to HTML internal format
* (e.c. '<' is replaced by '<'
METHODS: str2html IMPORTING i_str TYPE string
RETURNING value(e_str) TYPE string.
* Add string with or without conversion to internal format
METHODS: add_string IMPORTING str TYPE string,
add_string_raw IMPORTING str TYPE string.
* Moves content of internal line buffer to document (like new line).
METHODS: flush_buffer.
METHODS: add_tag_start IMPORTING tag TYPE string,
add_tag_end IMPORTING tag TYPE string,
add_tag IMPORTING tag TYPE string str TYPE string.
METHODS: add_header1 IMPORTING str TYPE string,
add_header2 IMPORTING str TYPE string,
add_header3 IMPORTING str TYPE string,
add_header4 IMPORTING str TYPE string,
add_header5 IMPORTING str TYPE string,
add_header6 IMPORTING str TYPE string,
add_paragraph IMPORTING str TYPE string,
add_line_break,
add_blank_line.
* Returns string (str...) or appends (add...) tag elements
* for links inside document. a_name is an anchor on a page,
* a_href is a refernce to an anchor. i_label must be unique
* identifier of an anchor. i_text is a text displayed as a reference.
METHODS: str_a_href IMPORTING i_label TYPE string
i_text TYPE string
RETURNING value(e_str) TYPE string,
str_a_name IMPORTING i_label TYPE string
i_text TYPE string
RETURNING value(e_str) TYPE string,
add_a_href IMPORTING i_label TYPE string
i_text TYPE string,
add_a_name IMPORTING i_label TYPE string
i_text TYPE string.
* Starts new document - place several tags
METHODS: start_document IMPORTING i_title TYPE string
i_code_page TYPE string
i_css_file_name TYPE string
i_comment TYPE string,
end_document.
* Writes HTML document to disk
METHODS: write_file IMPORTING file_name TYPE string
RETURNING value(ret_code) TYPE i.
PRIVATE SECTION.
DATA: lv_buffer TYPE string.
ENDCLASS. "zcl_ic_html DEFINITION
*----------------------------------------------------------------------*
* CLASS zcl_ic_html IMPLEMENTATION
*----------------------------------------------------------------------*
METHOD str2html.
DATA: str TYPE string,
len TYPE i, cur TYPE i, cnt TYPE i,
off1 TYPE i,
lv_char TYPE c, lv_spec(20) TYPE c.
off1 = 0.
len = STRLEN( i_str ).
DO len TIMES.
cur = sy-index - 1.
lv_char = i_str+cur(1).
CASE lv_char.
WHEN '<'.
lv_spec = '<'.
WHEN '>'.
lv_spec = '>'.
WHEN '&'.
lv_spec = '&'.
WHEN '|'.
lv_spec = '¦'.
WHEN '~'.
lv_spec = '˜'.
WHEN OTHERS.
IF sy-index = len. " last char
lv_spec = lv_char.
ELSE.
lv_spec = space.
ENDIF.
ENDCASE.
IF lv_spec <> space.
cnt = cur - off1.
CONCATENATE str i_str+off1(cnt) lv_spec INTO str.
off1 = sy-index.
ENDIF.
ENDDO.
e_str = str.
ENDMETHOD. "str2html
METHOD add_string.
DATA: txt TYPE string.
txt = str2html( str ).
CONCATENATE lv_buffer txt INTO lv_buffer.
ENDMETHOD. "add_string
METHOD add_string_raw.
CONCATENATE lv_buffer str INTO lv_buffer.
ENDMETHOD. "add_string_raw
METHOD flush_buffer.
IF NOT lv_buffer IS INITIAL.
APPEND lv_buffer TO gt_content.
CLEAR: lv_buffer.
ENDIF.
ENDMETHOD. "flush_buffer
METHOD add_header1.
CALL METHOD add_tag
EXPORTING
tag = 'h1'
str = str.
ENDMETHOD. "append_header1
METHOD add_header2.
CALL METHOD add_tag
EXPORTING
tag = 'h2'
str = str.
ENDMETHOD. "append_header2
METHOD add_header3.
CALL METHOD add_tag
EXPORTING
tag = 'h3'
str = str.
ENDMETHOD. "append_header3
METHOD add_header4.
CALL METHOD add_tag
EXPORTING
tag = 'h4'
str = str.
ENDMETHOD. "add_header4
METHOD add_header5.
CALL METHOD add_tag
EXPORTING
tag = 'h5'
str = str.
ENDMETHOD. "add_header5
METHOD add_header6.
CALL METHOD add_tag
EXPORTING
tag = 'h6'
str = str.
ENDMETHOD. "add_header6
METHOD add_paragraph.
CALL METHOD add_tag
EXPORTING
tag = 'p'
str = str.
ENDMETHOD. "append_paragraph
*&---------------------------------------------------------------------*
*& Include ZICDOC_CL_CODE_ANALYSIS
*&---------------------------------------------------------------------*
* @Author Ireneusz Cwir
* @Date June 2006
* @Info
* Definiotion and implementation of class CL_IC_CODE_ANALYSIS handling
* ABAP sorce code scan and analysis. Results of analysis are placed in
* several public tables. Class does not writes results of analysis
* to any devices - it must be done bu user of the class.
* Types defined to be used in the class and other programs.
* They are used to declare tables with results of analysis.
* Comment tag. Represents segment or section of code comments.
* Each segment starts with tag name: @NAME.
* If no tag is placed in the beginning of comment, INFO is used
* by default.
* All following lines of comment are concatenated into one string.
* Blank line can be used to finish comment (or any ABAP statemnt).
* To place line break, you can use HTML commands (like <br>).
* Comments:
* - Program level comment - starts with: *&. They are added in the
* beginning of include and by pretty-printer for forms.<br>
* - Function parameters - starts with: *" <br>
* - Other comments - start with *. <br>
* - Comments starting with " are ignored <br>
* - Obligatory to put SPACE after above chars <br>
* - Between program comment and following form comment there should be
* one blank line placed
* - Predefined comment variables (tags) start with: @ <br>
* - Comments can contain HTML formating commands <br>
* Comment section - starting with special tag (like @Author or @Info).
TYPES: BEGIN OF ts_commtag,
tag(30) TYPE c, " tag name (e.c. INFO, AUTHOR)
param(50) TYPE c, " optional parameter
text TYPE string, " text of comment
END OF ts_commtag.
TYPES: tt_commtag TYPE STANDARD TABLE OF ts_commtag
WITH DEFAULT KEY.
* Comment. Represents continuous part of code comments. It can consist
* of several tags (segments, sections).
TYPES: BEGIN OF ts_comment,
tags TYPE tt_commtag,
END OF ts_comment.
* Structure describing individual parameter of method, form, class
* declaration, etc. In the current version it is not implemented yet,
* so it contains just one dummy field. In the future, it can contain
* field for parameter name, type, import/export, etc.
TYPES: BEGIN OF ts_param_detail,
dummy TYPE c,
END OF ts_param_detail.
TYPES: tt_param_details TYPE STANDARD TABLE OF ts_param_detail
WITH DEFAULT KEY.
* Structure describing all parameters of single method, form, etc.
* At the moment, TEXT field containing the whole declaration. In the
* future, declaration cab further analyzed and split into individual
* parameters (name, type, etc.).
TYPES: BEGIN OF ts_parameters,
text TYPE string,
params TYPE tt_param_details,
END OF ts_parameters.
* Hierarchy of programs and includes (based on LEVELS returned by SCAN).
* For macros (DEFINE...) a special prog type is used ('9')
TYPES: BEGIN OF ts_program,
program TYPE programm, " Prog (include) name
subc TYPE subc, " Prog types (1=executable, ...)
title TYPE repti, " Report title
depth TYPE level_dpth, " Nesting depth of code unit
level TYPE level_levl, " Index of superior code unit
comment TYPE ts_comment, " Comment for program
END OF ts_program.
* Class/Interface parameters
* This structure is filled-up from class/interface definition.
TYPES: BEGIN OF ts_class,
clsname TYPE seoclsname, " Class/intf name
clstype TYPE seoclstype, " 0-class, 1-interface
program TYPE programm, " Program, Include name
super TYPE seoclsname, " Class/intf name of superclass
param TYPE ts_parameters, " Parameters
comment TYPE ts_comment, " Comment for class
END OF ts_class.
* Components of class/interface
* Components types:
* I - interface
* T - type
* C - constant
* A - aliases
* D - data
* CD - class-data
* M - method
* CM - class-method
* E - event
* CE - class-event
TYPES: t_clscmptype(2) TYPE c.
* This structure is filled-up from class/interface definition. For
* methods, additional comments are also placed in code units (from
* method implementation).
TYPES: BEGIN OF ts_classcmp,
clsname TYPE seoclsname, " Class/intf name
clstype TYPE seoclstype, " 0-class, 1-interface
exposure TYPE seoexpose, " 0-private, 1-protected, 2-public
cmpname TYPE seocmpname, " Component name
cmptype TYPE t_clscmptype, " Component type (see above)
param TYPE ts_parameters," Parameters
comment TYPE ts_comment, " Comment for component
END OF ts_classcmp.
TYPES: tt_classcmps TYPE STANDARD TABLE OF ts_classcmp.
* Type for code unit name. It must be long enough to store
* interface + ~ + method name
TYPES: t_unitname(70) TYPE c.
* Types of code modularization units and calls
* Types: F - form
* FM - function module
* CF - customer function
* B - BADI
* T - transaction
* E - main event (GET, INITIALIZATION, START-OF-SELECTION...
* CD - class definition
* CI - class implementation
* I - interface definition
* M - method
* S - submit program
TYPES: t_unittype(2) TYPE c.
* Source code modularization units details. It contains information
* from implementation.
TYPES: BEGIN OF ts_modunit,
name TYPE t_unitname, " Name of form, function, event,
type TYPE t_unittype, " Type of unit - see above
program TYPE programm, " Program, Include name
clsname TYPE seoclsname, " class name (required for methods)
param TYPE ts_parameters," Parameters (as string)
comment TYPE ts_comment, " Comment for unit
END OF ts_modunit.
* Hierarchy of code units calls
TYPES: BEGIN OF ts_unitshier,
name1 TYPE t_unitname, " Caller name (main)
type1 TYPE t_unittype, " Caller type (main)
prog1 TYPE programm, " Caller program (main)
clsname1 TYPE seoclsname, " Caller class name
name2 TYPE t_unitname, " Callee name (sub)
type2 TYPE t_unittype, " Callee type (sub)
depth TYPE level_dpth, " Nesting depth of call
END OF ts_unitshier.
* Database tables usage
* Access modes: T - Tables statement
* S - select (read)
* U - Update
* I - Insert
* M - Modify (U lub I)
* D - Delete
TYPES: t_dbaccmode TYPE c.
TYPES: BEGIN OF ts_dbtable,
table TYPE tabname, " Table name
mode TYPE t_dbaccmode," Access mode - see above
ddtext TYPE as4text, " Table description
program TYPE programm, " Program, Include
clsname TYPE seoclsname, " class name (required for methods)
name TYPE t_unitname, " Function or form name (access)
type TYPE t_unittype, " Module type
END OF ts_dbtable.
TYPES: tt_dbtables TYPE STANDARD TABLE OF ts_dbtable.
*----------------------------------------------------------------------*
* CLASS zcl_ic_code_analysis DEFINITION
*----------------------------------------------------------------------*
* Class contains methods used for source code analysis. Results are
* stored in atributes (tables) and they are not output. It must be
* done by another program (for instance subclas).
*----------------------------------------------------------------------*
CLASS zcl_ic_code_analysis DEFINITION.
PUBLIC SECTION.
* Main (root) program name - program, from which analysis starts
DATA: gv_main_program_name TYPE progname.
* Results of detailed analysis. They can be read by user of class
* and then displayed.
* Table contains hierarchy of includes (starting from main program).
DATA: gt_programs TYPE STANDARD TABLE OF ts_program,
* Table contains general information about classes and interfaces.
gt_classes TYPE STANDARD TABLE OF ts_class,
* Table contains components (attributes, methods) of classes and
* interfaces.
gt_classcmps TYPE STANDARD TABLE OF ts_classcmp,
* Table contains non-class code units (like forms, functions). As an
* exception, it contains comments for method implementation.
gt_modunits TYPE STANDARD TABLE OF ts_modunit,
* Table contains hierarchy of calls of code subunits (like calling
* form from anther one).
gt_unitshier TYPE STANDARD TABLE OF ts_unitshier,
* Table contans information about database tables affected by
* code units.
gt_dbtables TYPE STANDARD TABLE OF ts_dbtable.
METHODS: constructor.
* Resets (clears) all atributes of the object.
METHODS: reset.
* The main method which performs analysis of a program.
* Program must be available in the system.
* Results are stored in atribute tables (GT_XXX).
* @IMPORTING I_PROGRAM - The name of program in the system to be
* analyzed.
* @RETURNING RET_CODE - Returns result of analysis: 0-OK, <>0-error
METHODS: analyse_program IMPORTING i_program TYPE any
RETURNING value(ret_code) TYPE i,
* This method loads source code from the file and then performs
* analysis. With this method it is not possible to analyse
* nested includes.
* @IMPORTING I_FILENAME - The name with a path of program on local
* disk to loaded and analyzed.
* @RETURNING RET_CODE - Returns result of analysis: 0-OK, <>0-error
analyse_file IMPORTING i_filename TYPE string
RETURNING value(ret_code) TYPE i.
* Returns description of code unit type ('Form' for 'F'...).
METHODS: get_code_unit_type_desc IMPORTING i_type TYPE t_unittype
RETURNING value(e_desc) TYPE string,
* Returns desription of class component type ('Method' for 'M'...).
get_class_cmp_type_desc IMPORTING i_type TYPE t_clscmptype
RETURNING value(e_desc) TYPE string,
* Returns description of class exposure type ('Public' for '2')
get_class_cmp_exposure_desc IMPORTING i_exp TYPE seoexpose
RETURNING value(e_desc) TYPE string,
* Return description of database access mode ('Select' for 'S'...)
get_db_access_mode_desc IMPORTING i_mode TYPE t_dbaccmode
RETURNING value(e_desc) TYPE string.
" Helper funtions for testing
* Displays results of SCAN ABAP-CODE (dumps contents of returned
* tables). It helps understand results of built-in keyword.
* You will find very useful information in online help for
* keyword <code>SCAN ABAP-SOURCE<code>.
METHODS: dump_tables_scan,
* Displays individual statements and tokens with additional details.
* It also help understand results of SCAN keyword.
dump_statements_detailed,
* Displays statements (and tokens building statements) as source code
* lines. This is how ZICDOC sees source code after replacing
* INCLUDE with content of that program, unpacking statemts with ':'
* and other conversions.
dump_statements.
PROTECTED SECTION.
* COMPATYBILITY!!!!!
* For compatibility (SCAN keyword parameters changed in WAS)
TYPES: ts_token TYPE stokesx. " in >= WAS 6.10
* TYPES: begin of ts_token, " in R/3 4.6C
* str type string,
* row type TOKEN_ROW,
* OFF2 type TOKEN_OFF2,
* OFF3 type TOKEN_OFF3,
* COL type TOKEN_COL,
* LEN1 type TOKEN_LEN1,
* LEN2 type TOKEN_LEN2,
* LEN3 type TOKEN_LEN3,
* TYPE type TOKEN_TYPE,
* end of ts_token.
* Source code of a program
TYPES: BEGIN OF ts_srccode,
line(200) TYPE c,
END OF ts_srccode.
DATA: lt_srccode TYPE STANDARD TABLE OF ts_srccode.
* Direct results of SCAN ABAP-SOURCE
DATA: lt_tokens TYPE STANDARD TABLE OF ts_token,
* Direct results of SCAN ABAP-SOURCE
lt_statements TYPE STANDARD TABLE OF sstmnt ,
* Direct results of SCAN ABAP-SOURCE
lt_levels TYPE STANDARD TABLE OF slevel .
PRIVATE SECTION.
* Hierarchy of calls before further reworking.
DATA: lt_uhier TYPE STANDARD TABLE OF ts_unitshier.
* Current program, class and module unit during analysis
DATA: ls_cur_prog TYPE slevel,
ls_cur_class TYPE ts_class,
ls_cur_unit TYPE ts_modunit.
* The last read comment. It can be assigne to the next ABAP statement.
DATA: ls_last_comment TYPE ts_comment.
* Current statement and token during analysis
DATA: lv_cur_token_idx TYPE i,
lv_cur_stmnt_idx TYPE i.
DATA: ls_cur_stmnt TYPE sstmnt,
ls_cur_token TYPE ts_token.
* Performs analysis of source code loaded into private table. It is
* used by the main function of the class.
METHODS: do_analysis RETURNING value(ret_code) TYPE i.
" Analysis of specific statements groups
METHODS: do_events,
do_databases,
do_code_units,
do_classes,
do_class_components,
do_comments,
do_others.
* Reads the following tokens (starting from the next) and places
* them into parametr structure.
METHODS: do_parameters EXPORTING es_param TYPE ts_parameters.
* Fills-up current program nad module unit during analysis
METHODS: set_cur_prog,
set_cur_class IMPORTING i_clsname TYPE seoclsname
i_clstype TYPE seoclstype
i_super TYPE seoclsname
is_param TYPE ts_parameters,
set_cur_unit IMPORTING i_name TYPE t_unitname
i_type TYPE t_unittype
is_param TYPE ts_parameters.
* Appends current module unit to attribute table.
METHODS: append_cur_unit,
append_cur_class,
append_class_cmp IMPORTING is_clscmp TYPE ts_classcmp,
append_sub_unit IMPORTING i_name TYPE t_unitname
i_type TYPE t_unittype,
append_dbtable IMPORTING i_table TYPE tabname
i_mode TYPE c,
append_cur_prog_comment,
append_cur_class_comment,
append_cur_unit_comment,
append_comment.
METHODS: levels_to_programms,
rework_units_hier,
do_hier_path IMPORTING is_start TYPE ts_unitshier.
METHODS: get_first_statement EXPORTING es_stmnt TYPE sstmnt,
get_next_statement EXPORTING es_stmnt TYPE sstmnt,
get_cur_statement EXPORTING es_stmnt TYPE sstmnt,
get_first_token EXPORTING es_token TYPE ts_token,
get_next_token EXPORTING es_token TYPE ts_token,
get_cur_token EXPORTING es_token TYPE ts_token.
* Compatybility!!!!
METHODS: do_scan_code_46c RETURNING value(ret_code) TYPE i,
do_scan_code_610 RETURNING value(ret_code) TYPE i.
ENDCLASS. "zcl_ic_code_analysis DEFINITION
*----------------------------------------------------------------------*
* CLASS zcl_ic_code_analysis IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS zcl_ic_code_analysis IMPLEMENTATION.
* Clears all atributes. It is not necessary, but just to do anything.
METHOD constructor.
CALL METHOD reset.
ENDMETHOD. "constructor
CASE i_type.
WHEN 'F'.
e_desc = 'Form'.
WHEN 'FM'.
e_desc = 'Function module'.
WHEN 'CF'.
e_desc = 'Customer function'.
WHEN 'B'.
e_desc = 'BADi'.
WHEN 'T'.
e_desc = 'Transaction'.
WHEN 'E'.
e_desc = 'List event'.
WHEN 'S'.
e_desc = 'Submit program'.
WHEN 'CD'.
e_desc = 'Class definition'.
WHEN 'CI'.
e_desc = 'Class implementation'.
WHEN 'I'.
e_desc = 'Interface'.
WHEN 'M'.
e_desc = 'Method'. " Must be the same as in the next method
ENDCASE.
ENDMETHOD. "get_code_unit_type_desc
* Returns description of class component type.
METHOD get_class_cmp_type_desc.
CASE i_type.
WHEN 'T'.
e_desc = 'Type'.
WHEN 'C'.
e_desc = 'Constant'.
WHEN 'I'.
e_desc = 'Interface'.
WHEN 'A'.
e_desc = 'Alias'.
WHEN 'D'.
e_desc = 'Data'.
WHEN 'CD'.
e_desc = 'Class-data'.
WHEN 'M'.
e_desc = 'Method'. " Must be the same as in the prev method
WHEN 'CM'.
e_desc = 'Class-method'.
WHEN 'E'.
e_desc = 'Event'.
WHEN 'CE'.
e_desc = 'Class-event'.
ENDCASE.
ENDMETHOD. "get_class_cmp_type_desc
* Returns description of class component exposure.
METHOD get_class_cmp_exposure_desc.
CASE i_exp.
WHEN '0'.
e_desc = 'Private'.
WHEN '1'.
e_desc = 'Protected'.
WHEN '2'.
e_desc = 'Public'.
ENDCASE.
ENDMETHOD. "get_class_cmp_exposure_desc
* Returns description of database access mode.
METHOD get_db_access_mode_desc.
CASE i_mode.
WHEN 'T'.
e_desc = 'Table'.
WHEN 'S'.
e_desc = 'Select'.
WHEN 'U'.
e_desc = 'Update'.
WHEN 'I'.
e_desc = 'Insert'.
WHEN 'M'.
e_desc = 'Modify (U,I)'.
WHEN 'D'.
e_desc = 'Delete'.
ENDCASE.
* Store the main (starting) program name and analyze code.
gv_main_program_name = i_filename.
TRANSLATE gv_main_program_name TO UPPER CASE.
CALL METHOD do_analysis
RECEIVING
ret_code = ret_code.
* Scans source code - to be used in version 4.6.
* Statement SCAN ABAP_SOURCE behaves in different way in system
* 4.6 and >= WAS 6.1. It uses other types of parameters.
METHOD do_scan_code_46c.
DATA: lt_tok TYPE STANDARD TABLE OF stokex,
ls_tok TYPE stokex,
ls_token TYPE ts_token,
lv_over(65535) TYPE c.
* COMPATYBILITY!!!!!
* SCAN ABAP-SOURCE lt_srccode TOKENS INTO lt_tok
* OVERFLOW INTO lv_over
* STATEMENTS INTO lt_statements
* WITH ANALYSIS
* WITH INCLUDES LEVELS INTO lt_levels
* WITH COMMENTS.
* ret_code = sy-subrc.
** Konwersja do formatu z 6.10 (STOKESX)
* LOOP AT lt_tok INTO ls_tok.
* MOVE-CORRESPONDING ls_tok TO ls_token.
* IF ls_tok-ovfl <> space.
* ls_token-str = lv_over+ls_tok-off1(ls_tok-len).
* ENDIF.
* APPEND ls_token TO lt_tokens.
* ENDLOOP.
ENDMETHOD. "do_analyse_46C
* Scans source code - to be used in version WAS 6.1 and newer.
METHOD do_scan_code_610.
* COMPATYBILITY!!!!!
SCAN ABAP-SOURCE lt_srccode TOKENS INTO lt_tokens
STATEMENTS INTO lt_statements
WITH ANALYSIS
WITH INCLUDES LEVELS INTO lt_levels
WITH COMMENTS.
ret_code = sy-subrc.
* The main method performing analysis of loaded source code.
* It scans source code and then converts returned tables into tables
* used later for documentation generation (global attributes).
METHOD do_analysis.
DATA: ls_stmnt TYPE sstmnt,
ls_token TYPE ts_token.
* Scan source code and fill tables of statements and tokens
IF sy-saprl >= '610'.
CALL METHOD do_scan_code_610
RECEIVING
ret_code = ret_code.
ELSE.
CALL METHOD do_scan_code_46c
RECEIVING
ret_code = ret_code.
ENDIF.
CHECK ret_code < 4.
ret_code = 0.
* Convert levels into GT_PROGRAMS
CALL METHOD levels_to_programms.
* Analyse statements of code one-by-one
CALL METHOD get_first_statement
IMPORTING
es_stmnt = ls_stmnt.
WHILE ls_stmnt-type <> space.
* For comments - they recognized by statemnt type.
IF ls_stmnt-type = 'P'.
CALL METHOD do_comments.
* For other keywords
ELSE.
* The first token of the current statement
CALL METHOD get_first_token
IMPORTING
es_token = ls_token.
CASE ls_token-str.
WHEN 'START-OF-SELECTION' OR
'END-OF-SELECTION' OR
'INITIALIZATION' OR
'GET' OR
'AT'.
CALL METHOD do_events.
WHEN 'TABLES' OR
'SELECT' OR
'UPDATE' OR
'INSERT' OR
'MODIFY' OR
'DELETE'.
CALL METHOD do_databases.
WHEN 'FORM' OR
'ENDFORM' OR
'FUNCTION' OR
'ENDFUNCTION' OR
'METHOD' OR
'ENDMETHOD' OR
'PERFORM' OR
'CALL' OR
'SUBMIT'.
CALL METHOD do_code_units.
WHEN 'CLASS' OR
'ENDCLASS' OR
'INTERFACE' OR
'ENDINTERFACE'.
CALL METHOD do_classes.
WHEN OTHERS.
CALL METHOD do_others.
ENDCASE.
CLEAR: ls_last_comment.
ENDIF.
* For AT, we use two tokens to build name
IF ls_token-str = 'AT'.
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
CONCATENATE l_name ls_token-str INTO l_name SEPARATED BY space.
ENDIF.
* The rest of tokens builds parameter
CALL METHOD do_parameters
IMPORTING
es_param = ls_param.
WHEN 'FUNCTION' OR
'METHOD'.
l_type = 'FM'.
IF ls_token-str = 'METHOD'.
l_type = 'M'.
ENDIF.
* Name
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
l_name = ls_token-str.
CALL METHOD set_cur_unit
EXPORTING
i_name = l_name
i_type = l_type
is_param = ls_param.
CALL METHOD append_cur_unit.
* In case of interface method implementation, it is not added to
* class components from class definition. We must do there.
* We can call function for all methods (not only interfaces).
IF l_type = 'M'.
ls_cmp-cmpname = l_name.
ls_cmp-cmptype = l_type.
ls_cmp-clsname = ls_cur_class-clsname..
ls_cmp-clstype = '0'.
ls_cmp-exposure = '2'.
CALL METHOD append_class_cmp
EXPORTING
is_clscmp = ls_cmp.
ENDIF.
WHEN 'ENDFORM' OR
'ENDMETHOD' OR
'ENDFUNCTION'.
CLEAR: ls_cur_unit.
WHEN 'PERFORM' OR
'SUBMIT'.
l_type = 'F'.
IF ls_token-str = 'SUBMIT'.
l_type = 'S'.
ENDIF.
* Name
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
l_name = ls_token-str.
CALL METHOD append_sub_unit
EXPORTING
i_name = l_name
i_type = l_type.
WHEN 'CALL'.
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
* Check the secont part of call
CASE ls_token-str.
WHEN 'FUNCTION'.
l_type = 'FM'.
WHEN 'CUSTOMER-FUNCTION'.
l_type = 'CF'.
WHEN 'BADI'.
l_type = 'B'.
WHEN 'METHOD'.
l_type = 'M'.
WHEN 'TRANSATION'.
l_type = 'T'.
ENDCASE.
IF l_type <> space.
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
l_name = ls_token-str.
CALL METHOD append_sub_unit
EXPORTING
i_name = l_name
i_type = l_type.
ENDIF.
ENDCASE.
ENDMETHOD. "do_calls
* Performs analysis of statement representing definition and
* implementation of classes.
METHOD do_classes.
DATA: ls_token TYPE ts_token,
ls_param TYPE ts_parameters.
DATA: l_name TYPE t_unitname,
l_clsname TYPE seoclsname,
l_super TYPE seoclsname,
l_type TYPE t_unittype,
l_clstype TYPE seoclstype.
WHEN 'CLASS' OR
'INTERFACE'.
l_clstype = '0'. " class
IF ls_token-str = 'INTERFACE'.
l_clstype = '1'. " interface
l_type = 'I'.
ENDIF.
* Get class name
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
l_clsname = ls_token-str.
* Get parameters for analysing special parameters of class.
* They are not stored in dedicated components - it will be done
* in the second run.
WHILE ls_token-str <> space.
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
CASE ls_token-str.
* Skip these types of declartions
WHEN 'DEFERRED' OR
'LOAD'.
RETURN.
WHEN 'DEFINITION'.
l_type = 'CD'.
WHEN 'IMPLEMENTATION'.
l_type = 'CI'.
WHEN 'FROM'.
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
l_super = ls_token-str.
ENDCASE.
ENDWHILE.
* The second run for filling standard component
* First, we must skip starting keywords
CALL METHOD get_first_token
IMPORTING
es_token = ls_token.
DO 2 TIMES.
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
ENDDO.
* set_cur_class must be called before set_cur_unit
CALL METHOD set_cur_class
EXPORTING
i_clsname = l_clsname
i_clstype = l_clstype
i_super = l_super
is_param = ls_param.
l_name = l_clsname.
CALL METHOD set_cur_unit
EXPORTING
i_name = l_name
i_type = l_type
is_param = ls_param.
CALL METHOD append_cur_unit.
* For interface and class definition
IF l_type = 'I' OR l_type = 'CD'.
CALL METHOD append_cur_class.
* Analyse components of class/interface
CALL METHOD do_class_components.
CLEAR: ls_cur_unit,
ls_cur_class.
ENDIF.
WHEN 'ENDCLASS' OR
'ENDINTERFACE'.
CLEAR: ls_cur_unit,
ls_cur_class.
ENDCASE.
ENDMETHOD. "do_classes
* Performs analysis of class definition - stores components.
METHOD do_class_components.
DATA: ls_stmnt TYPE sstmnt,
ls_token TYPE ts_token.
DATA: ls_cmp TYPE ts_classcmp.
* Set default values
ls_cmp-exposure = 2. " Public
* Method is called from CLASS / INTERFACE statement, so need the next
CALL METHOD get_next_statement
IMPORTING
es_stmnt = ls_stmnt.
WHILE ls_stmnt-type <> space.
* We must handle comments
IF ls_stmnt-type = 'P'.
CALL METHOD do_comments.
ELSE.
* The first token of the current statement
CALL METHOD get_first_token
IMPORTING
es_token = ls_token.
CASE ls_token-str.
WHEN 'ENDCLASS' OR
'ENDINTERFACE'.
EXIT.
WHEN 'PUBLIC'.
ls_cmp-exposure = '2'.
WHEN 'PROTECTED'.
ls_cmp-exposure = '1'.
WHEN 'PRIVATE'.
ls_cmp-exposure = '0'.
WHEN 'TYPES'.
ls_cmp-cmptype = 'T'.
WHEN 'CONSTANTS'.
ls_cmp-cmptype = 'C'.
WHEN 'INTERFACES'.
ls_cmp-cmptype = 'I'.
WHEN 'ALIASES'.
ls_cmp-cmptype = 'A'.
WHEN 'DATA'.
ls_cmp-cmptype = 'D'.
WHEN 'CLASS-DATA'.
ls_cmp-cmptype = 'CD'.
WHEN 'METHODS'.
ls_cmp-cmptype = 'M'.
WHEN 'CLASS-METHODS'.
ls_cmp-cmptype = 'CM'.
WHEN 'EVENTS'.
ls_cmp-cmptype = 'E'.
WHEN 'CLASS-EVENTS'.
ls_cmp-cmptype = 'CE'.
ENDCASE.
* If CLSTYPE set, then we have component
IF ls_cmp-cmptype IS NOT INITIAL.
* The next token contains name
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
ls_cmp-cmpname = ls_token-str.
* Performs analysis of continuous code section of comments. If we
* enter several lines of comments, even with balnk lines inside,
* SCAN returns them as one statemnt (each line will be separate token).
* Results are placed in structure and can be used by by other methods.
* Typically, coments are placed BEFORE code we are interested in.
* Comment is stored in LS_LAST_COMMENT atribute.
METHOD do_comments.
DATA: ls_token TYPE ts_token,
ls_tag TYPE ts_commtag.
DATA: l_str TYPE string,
l_buf TYPE string.
DATA: l_comm_type TYPE c,
l_char TYPE c.
DATA: l_last_row TYPE i,
l_len TYPE i,
l_offs TYPE i.
* Analyse all lines of comment
WHILE ls_token-str <> space.
l_len = STRLEN( ls_token-str ).
* Process only comments starting with '*' or " in the first column
IF l_len >= 1 AND ls_token-str(1) = '"' AND ls_token-col > 0.
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
CONTINUE.
ENDIF.
* Set comment type (program, function or other). It is called for
* the first line of the comment (also after blank line).
IF l_comm_type = space.
IF l_len >= 2 AND ls_token-str(2) = '*&'.
l_comm_type = 'P'. " like program beginning
ELSEIF l_len >= 2 AND ls_token-str(2) = '*"'.
l_comm_type = 'F'. " like function parameters
ELSE.
l_comm_type = 'O'. " other comments
ENDIF.
ENDIF.
* Check if blank lines appeares between lines of comment. Blank line
* ends the current part of comment.
l_offs = ls_token-row - l_last_row.
l_last_row = ls_token-row.
IF l_offs > 1.
IF l_comm_type = 'P' OR l_comm_type = 'F'.
IF ls_tag-text <> space.
APPEND ls_tag TO ls_last_comment-tags.
ENDIF.
CALL METHOD append_comment.
ENDIF.
* Starting next paragraph
CLEAR: ls_tag.
CLEAR: l_comm_type.
CONTINUE.
ENDIF.
* Ommit semi-lines (strings of the same characters)
l_len = STRLEN( ls_token-str ).
IF l_len >= 6 AND ls_token-str+3(1) = ls_token-str+4(1) AND
ls_token-str+3(1) = ls_token-str+5(1).
l_char = ls_token-str+3(1).
IF l_char <> space.
IF ls_tag-text <> space.
APPEND ls_tag TO ls_last_comment-tags.
ENDIF.
CLEAR: ls_tag.
CALL METHOD get_next_token
IMPORTING
es_token = ls_token.
CONTINUE.
ENDIF.
ENDIF.
* Remove beginning markers
l_len = STRLEN( ls_token-str ).
l_offs = 0.
WHILE l_offs < l_len AND ls_token-str+l_offs(1) CA '*"& '.
l_offs = l_offs + 1.
ENDWHILE.
l_str = ls_token-str+l_offs.
* Special tags in comments (starting with '@')
l_len = STRLEN( l_str ).
IF l_len > 0.
IF l_str(1) = '@'.
IF ls_tag-text <> space.
APPEND ls_tag TO ls_last_comment-tags.
ENDIF.
CLEAR: ls_tag.
SPLIT l_str+1 AT space INTO ls_tag-tag l_buf.
TRANSLATE ls_tag-tag TO UPPER CASE.
* Tags with parameters
IF ls_tag-tag = 'PARAM' OR ls_tag-tag = 'TABLES' OR
ls_tag-tag = 'USING' OR
ls_tag-tag = 'IMPORT' OR ls_tag-tag = 'IMPORTING' OR
ls_tag-tag = 'EXPORT' OR ls_tag-tag = 'EXPORTING' OR
ls_tag-tag = 'CHANGE' OR ls_tag-tag = 'CHANGING' OR
ls_tag-tag = 'RETURN' OR ls_tag-tag = 'RETURNING' OR
ls_tag-tag = 'RECEIVING' OR
ls_tag-tag = 'EXCEPTION' OR ls_tag-tag = 'THROWS' OR
ls_tag-tag = 'RAISING'.
CLEAR: l_buf.
SPLIT l_str+1 AT space INTO ls_tag-tag ls_tag-param l_buf.
TRANSLATE ls_tag-tag TO UPPER CASE.
ENDIF.
ls_tag-text = l_buf.
ELSE.
CONCATENATE ls_tag-text l_str INTO ls_tag-text
SEPARATED BY space.
SHIFT ls_tag-text LEFT DELETING LEADING space.
IF ls_tag-tag = space.
ls_tag-tag = 'INFO'.
ENDIF.
ENDIF.
ENDIF.
* Appends parameters (declaration) of current class to results table
METHOD append_cur_class.
CHECK ls_cur_class-clsname IS NOT INITIAL.
APPEND ls_cur_class TO gt_classes.
ENDMETHOD. "append_cur_func
* Append class component to result table.
METHOD append_class_cmp.
DATA: ls_cmp TYPE ts_classcmp.
DATA: l_tabix TYPE syst-tabix.
CHECK is_clscmp-cmpname IS NOT INITIAL.
* Check if table already contains component. It can be called twice:
* for definition and implementation. For the first time we populate
* more fields than for the second.
READ TABLE gt_classcmps INTO ls_cmp
WITH KEY clsname = ls_cur_class-clsname
clstype = ls_cur_class-clstype
cmpname = is_clscmp-cmpname.
* If already exists - update comment only
IF sy-subrc = 0.
l_tabix = sy-tabix.
APPEND LINES OF ls_last_comment-tags TO ls_cmp-comment-tags.
MODIFY gt_classcmps INDEX l_tabix FROM ls_cmp
TRANSPORTING comment.
* Append new component
ELSE.
ls_cmp = is_clscmp.
ls_cmp-clsname = ls_cur_class-clsname.
ls_cmp-clstype = ls_cur_class-clstype.
ls_cmp-comment = ls_last_comment.
APPEND ls_cmp TO gt_classcmps.
ENDIF.
CLEAR: ls_last_comment.
ENDMETHOD. "append_class_cmp
* Appends parameters of current code unit to results table.
METHOD append_cur_unit.
CHECK ls_cur_unit-name IS NOT INITIAL.
APPEND ls_cur_unit TO gt_modunits.
ENDMETHOD. "append_cur_unit
* Appends information about sub code unit called from current unit
* Called from PERFORM..., CALL... etc.
METHOD append_sub_unit.
DATA: ls_unitshier TYPE ts_unitshier.
ls_unitshier-name1 = ls_cur_unit-name.
ls_unitshier-type1 = ls_cur_unit-type.
ls_unitshier-prog1 = ls_cur_unit-program.
ls_unitshier-clsname1 = ls_cur_class-clsname.
ls_unitshier-name2 = i_name.
ls_unitshier-type2 = i_type.
CHECK ls_unitshier-name1 <> space AND ls_unitshier-name2 <> space.
APPEND ls_unitshier TO lt_uhier.
ENDMETHOD. "append_sub_func
* Appends information about access to database table.
METHOD append_dbtable.
DATA: ls_dbtable TYPE ts_dbtable.
DATA: lv_tabclass TYPE tabclass.
* If table name is provided dynamically - just store information.
* If statically - check and get table parameters in DDIC.
IF i_table(1) <> '('.
* Check if table exists and get description.
SELECT SINGLE tabclass INTO (lv_tabclass) FROM dd02l
WHERE tabname = i_table.
IF sy-subrc <> 0.
EXIT.
ENDIF.
SELECT SINGLE ddtext INTO (ls_dbtable-ddtext) FROM dd02t
WHERE tabname = i_table
AND ddlanguage = sy-langu
AND as4local = 'A'.
ENDIF.
ls_dbtable-table = i_table.
ls_dbtable-mode = i_mode.
ls_dbtable-program = ls_cur_prog-name.
ls_dbtable-clsname = ls_cur_class-clsname.
ls_dbtable-name = ls_cur_unit-name.
ls_dbtable-type = ls_cur_unit-type.
COLLECT ls_dbtable INTO gt_dbtables.
ENDMETHOD. "append_dbtable
* Appends last comment to the current program (include). Appends only
* if is not entered yet. It is because comments beginning with *&
* are added by pretty-printer for forms.
METHOD append_cur_prog_comment.
DATA: ls_prog TYPE ts_program.
DATA: l_tabix TYPE sy-tabix.
* This comment must be outside code unit
IF ls_cur_unit-name IS INITIAL.
* Store program comment only if it is empty yet.
READ TABLE gt_programs INTO ls_prog
WITH KEY program = ls_cur_prog-name.
IF sy-subrc = 0 AND ls_prog-comment IS INITIAL.
l_tabix = sy-tabix.
ls_prog-comment = ls_last_comment.
MODIFY gt_programs FROM ls_prog INDEX l_tabix.
CLEAR: ls_last_comment. " only if appended
ENDIF.
ENDIF.
ENDMETHOD. "append_prog_comment
* Appends last comment to the current class (general level).
METHOD append_cur_class_comment.
DATA: ls_class TYPE ts_class.
DATA: l_tabix TYPE sy-tabix.
READ TABLE gt_classes INTO ls_class
WITH KEY clsname = ls_cur_class-clsname
clstype = ls_cur_class-clstype.
IF sy-subrc = 0.
l_tabix = sy-tabix.
IF ls_class-comment IS INITIAL.
ls_class-comment = ls_last_comment.
ELSE.
APPEND LINES OF ls_last_comment-tags TO ls_class-comment-tags.
ENDIF.
MODIFY gt_classes FROM ls_class INDEX l_tabix.
ENDIF.
CLEAR: ls_last_comment.
ENDMETHOD. "append_prog_comment
* Appends last comment to the current code unit.
METHOD append_cur_unit_comment.
DATA: ls_unit TYPE ts_modunit.
DATA: l_tabix TYPE sy-tabix.
READ TABLE gt_modunits INTO ls_unit
WITH KEY name = ls_cur_unit-name
type = ls_cur_unit-type.
IF sy-subrc = 0.
l_tabix = sy-tabix.
IF ls_unit-comment IS INITIAL.
ls_unit-comment = ls_last_comment.
ELSE.
APPEND LINES OF ls_last_comment-tags TO ls_unit-comment-tags.
ENDIF.
MODIFY gt_modunits FROM ls_unit INDEX l_tabix.
ENDIF.
CLEAR: ls_last_comment.
ENDMETHOD. "append_cur_unit_comment
* Appends comment to right object - depends, if it is inside form or
* class or outside them
METHOD append_comment.
* If inside code unit, comment is added to this unit
IF ls_cur_unit-name IS NOT INITIAL.
CALL METHOD append_cur_unit_comment.
* If inside class definition/implementation (but outside method)
ELSEIF ls_cur_class-clsname IS NOT INITIAL.
CALL METHOD append_cur_class_comment.
* In other cases add to program's comment
ELSEIF ls_cur_prog-name IS NOT INITIAL.
CALL METHOD append_cur_prog_comment.
ENDIF.
ENDMETHOD. "append_comment
* Converts program levels (raw results of SCAN ABAP-CODE) into more
* suitable format of global table GT_PROGRAMS
METHOD levels_to_programms.
DATA: ls_level TYPE slevel,
ls_prog TYPE ts_program.
* Convert levels into GT_PROGRAMS
LOOP AT lt_levels INTO ls_level.
* For macros
IF ls_level-type = 'D'.
ls_prog-subc = '9'. " non-standard
ls_prog-title = 'User macro'.
* Each call of macro is placed in the table, so we maust check
* if already appended
READ TABLE gt_programs TRANSPORTING NO FIELDS WITH KEY
program = ls_prog-program
depth = ls_prog-depth.
CHECK sy-subrc <> 0.
* Main program, include (type = P)
ELSE.
* Get program type (1, ...)
SELECT SINGLE subc INTO (ls_prog-subc) FROM trdir
WHERE name = ls_prog-program.
* Title of the program is determined from program's properties
* in logon language, or in EN/DE or in any available.
SELECT SINGLE text INTO (ls_prog-title) FROM trdirt
WHERE name = ls_prog-program
AND sprsl = sy-langu.
IF sy-subrc <> 0.
SELECT SINGLE text INTO (ls_prog-title) FROM trdirt
WHERE name = ls_prog-program
AND sprsl IN ('E', 'D').
IF sy-subrc <> 0.
SELECT SINGLE text INTO (ls_prog-title) FROM trdirt
WHERE name = ls_prog-program.
ENDIF.
ENDIF.
ENDIF.
APPEND ls_prog TO gt_programs.
ENDLOOP.
ENDMETHOD. "levels_to_programms
* Converts results code analysis (hierarchy of code units calls)
* into format more suitable for further processing.
METHOD rework_units_hier.
DATA: ls_hier TYPE ts_unitshier,
ls_prog TYPE ts_program,
ls_unit TYPE ts_modunit.
* If main program is an executable (type 1) program we will start
* with events in main program
READ TABLE gt_programs INTO ls_prog INDEX 1.
IF ls_prog-subc = '1'.
LOOP AT gt_modunits INTO ls_unit WHERE program = ls_prog-program
AND type = 'E'.
CLEAR: ls_hier.
ls_hier-name2 = ls_unit-name.
ls_hier-type2 = ls_unit-type.
ls_hier-prog1 = ls_unit-program.
ls_hier-clsname1 = ls_unit-clsname.
ls_hier-depth = '1'.
CALL METHOD do_hier_path( ls_hier ).
ENDLOOP.
* For other program types, we go through all programs and build
* tree for every unit which has no caller
ELSE.
LOOP AT gt_programs INTO ls_prog.
LOOP AT gt_modunits INTO ls_unit
WHERE program = ls_prog-program.
* Check if it has caller
READ TABLE lt_uhier WITH KEY name2 = ls_unit-name
type2 = ls_unit-type
TRANSPORTING NO FIELDS.
IF sy-subrc <> 0.
CLEAR: ls_hier.
ls_hier-name2 = ls_unit-name.
ls_hier-type2 = ls_unit-type.
ls_hier-prog1 = ls_unit-program.
ls_hier-clsname1 = ls_unit-clsname.
ls_hier-depth = '1'.
CALL METHOD do_hier_path( ls_hier ).
ENDIF.
ENDLOOP.
ENDLOOP.
ENDIF.
ENDMETHOD. "rework_units_hier
* This method does not work for calls cycles (a->b and b->a)
METHOD do_hier_path. " importing is_start type ts_unitshier
DATA: ls_hier TYPE ts_unitshier.
APPEND is_start TO gt_unitshier.
LOOP AT lt_uhier INTO ls_hier WHERE name1 = is_start-name2
AND type1 = is_start-type2.
ls_hier-depth = is_start-depth + 1.
CALL METHOD do_hier_path( ls_hier ).
ENDLOOP.
*======================================================================
* The followinh methods are used for test purposes - they dump
* to the screen results of SCAN ABAP-CODE.
* Displays all statements and tokens with details (type, level, posit.).
METHOD dump_statements_detailed.
DATA: l_stmnt TYPE sstmnt,
l_token TYPE ts_token.
WRITE:/ 'Program:', gv_main_program_name.
WRITE: / '==================================================='.
WRITE: / 'S T A T E M E N T S D E T A I L S'.
WRITE: / '==================================================='.
* Displays statements as lines of code (one code = one line).
METHOD dump_statements.
DATA: l_stmnt TYPE sstmnt,
l_token TYPE ts_token.
WRITE:/ 'Program:', gv_main_program_name.
WRITE: / '==================================================='.
WRITE: / 'S T A T E M E N T S'.
WRITE: / '==================================================='.
* Displays content of tables returned by SCAN ABAP-CODE.
METHOD dump_tables_scan.
DATA: ls_srccode TYPE string,
ls_tokens TYPE ts_token ,
ls_statements TYPE sstmnt,
ls_levels TYPE slevel.
WRITE:/ 'Program:', gv_main_program_name.
WRITE: / '==================================================='.
WRITE: / 'T O K E N S'.
WRITE:/ ' Lp. TYPE ROW OFF2 OFF3',
' COL LEN1 LEN2 LEN3 STR'.
WRITE: / '==================================================='.
LOOP AT lt_tokens INTO ls_tokens.
WRITE:/ sy-tabix,
ls_tokens-type, ls_tokens-row, ls_tokens-off2,
ls_tokens-off3, ls_tokens-col,
ls_tokens-len1, ls_tokens-len2, ls_tokens-len3,
ls_tokens-str.
ENDLOOP.
WRITE: / '==================================================='.
WRITE: / 'S T A T E M E N T S'.
WRITE: / ' Lp. LEVEL STRUC FROM TO',
' NUMBER COLONROW TROW COCOL TCOL PRLEN',
' TYPE.TERM ENHMT'.
WRITE: / '==================================================='.
LOOP AT lt_statements INTO ls_statements.
WRITE:/ sy-tabix,
ls_statements-level, ls_statements-struc,
ls_statements-from,
ls_statements-to, ls_statements-number,
ls_statements-colonrow, ls_statements-trow,
ls_statements-coloncol, ls_statements-tcol,
ls_statements-prefixlen, ls_statements-type,
ls_statements-terminator. ", ls_statements-enhmt.
ENDLOOP.
WRITE: / '==================================================='.
WRITE: / 'L E V E L S'.
WRITE: / ' Lp. DEPTH LEVEL STMNT',
' FROM TO TYPE NAME'.
WRITE: / '==================================================='.
LOOP AT lt_levels INTO ls_levels.
WRITE:/ sy-tabix,
ls_levels-depth, ls_levels-level, ls_levels-stmnt,
ls_levels-from, ls_levels-to,
ls_levels-type, ls_levels-name.
ENDLOOP.
* WRITE: / '==================================================='.
* WRITE: / 'S T R U C T U R E S'.
* WRITE: / ' Lp. TYPE STMNT_TYPE K_START KEY_END',
* ' STMNT_FROM STMNT_TO STRUC_FROM STRUC_TO',
* ' BACK'.
* WRITE: / '==================================================='.
* LOOP AT gt_structures.
* WRITE:/ sy-tabix,
* gt_structures-type, ' ',
* gt_structures-stmnt_type, ' ',
* gt_structures-key_start, ' ',
* gt_structures-key_end, ' ',
* gt_structures-stmnt_from, gt_structures-stmnt_to,
* gt_structures-struc_from, gt_structures-struc_to,
* gt_structures-back.
* ENDLOOP.
*&---------------------------------------------------------------------*
*& Include ZICDOC_CL_CODE_ANALYSIS_HTML
*&---------------------------------------------------------------------*
* @Author Ireneusz Cwir
* @Date June 2006
* @Info Include contains definition and implementation of class
* ZCL_IC_CODE_ANALYSIS_HTML. This class handles analysis of ABAP
* program and creation of HTML file with analysis results.
* The class uses class ZCL_IC_CODE_ANALYSIS to scan source code and
* store results in public tables. This class reads these tables and
* writes HTML file.
* HTML document creation is handled by class ZCL_IC_HTML.
INCLUDE zicdoc_cl_code_analysis.
INCLUDE zicdoc_cl_html.
* Texts and templates used for creation of HTML file
* They must be in HTML source format (ec. '<' for displaying '<')
* Variables in templates should have format: @n@,
* where n = number of paparmeter
*
* Section 0 - general data (document header)
* Section 1 - programs and includes hierarchy
* Section 2 - database tables used in programs
* Section 3 - programs and includes summary
* Section 4 - class components
* Section 5 - non-class code units
* Section 6 - code units calls hierarchy
* Code page placed in document header
CONSTANTS: c_html_code_page TYPE string VALUE 'windows-1250'.
* Cascade style sheet (CSS) file name (with path)
CONSTANTS: c_css_file_name TYPE string VALUE 'ZIcDocStyle.css'.
* A kind of info about author of the tool
CONSTANTS: c_zicdoc_author TYPE string VALUE
'<!-- Genereted by ZICDOC, by Ireneusz Cwir -->'.
* HTML title (displayed in explorer window's title)
CONSTANTS: c_html_title TYPE string VALUE
'@1@ - Source code documentation'.
* Sections' headers
CONSTANTS: c_html_header_0 TYPE string VALUE
'<h1>@1@ - Source code documentation</h1><br>',
c_html_header_1 TYPE string VALUE
'<br><h2>Programs and includes</h2><br>',
c_html_header_2 TYPE string VALUE
'<br><h2>Database tables</h2><br>',
c_html_header_3 TYPE string VALUE
'<br><h2>Programs and includes summary</h2><br>',
c_html_header_4 TYPE string VALUE
'<br><h2>Class components</h2><br>',
c_html_header_5 TYPE string VALUE
'<br><h2>Non-class code units</h2><br>',
c_html_header_6 TYPE string VALUE
'<br><h2>Code units calls hierarchy</h2><br>'.
* General templates
CONSTANTS:
* Template for writting all elements of comment. variables are for:
* 1. Tag, 2. Parameter, 3. Text of comment
c_html_comment_complex TYPE string VALUE
'<dl><dt>@1@</dt><dd><var>@2@ </var>@3@</dd></dl>',
* Code unit details - header. 1. Unit name
c_html_unit_det_header TYPE string VALUE
'<hr><h5>@1@</h5>',
* Code unit details - Declaration. 1. Unit name, 2. Type, 3. Params
c_html_unit_det_declaration TYPE string VALUE
'<dl><dt><code>@2@ @1@</code></dt><dd><code>@3@</code></dd></dl>'.
* For section 1 - hierarchy of includes
* Prefix representing next level of nesting of include (like . )
CONSTANTS: c_html_s1_nesting_level TYPE string VALUE '. ',
* Style for placing program name
c_html_s1_program_name TYPE string VALUE
'<dfn>@1@</dfn><br>'.
* For section 2 - database tables
* Short info
CONSTANTS: c_html_s2_sub_header TYPE string VALUE
'<h4>Database tables access:</h4>',
* Line of HTML table containing info about database table
* 1. Table name, 2. Access mode, 3. Table description from DDIC
c_html_s2_db_table_info TYPE string VALUE
'<tr><td class="dbname"><dfn>@1@</dfn></td>' &
'<td class="dbaccess">@2@</td>' &
'<td>@3@</td></tr>'.
* For section 3 - includes summary
CONSTANTS:
* Program name (as a section header)
c_html_s3_program TYPE string VALUE
'<h3>@1@</h3>',
* Program title (description from dictionary)
c_html_s3_title TYPE string VALUE
'<table><tr><td><samp>Title:</samp></td><td>@1@</td></tr></table>',
* Header for code units list
c_html_s3_units TYPE string VALUE
'<h4>Forms, events, functions:</h4>',
* Table line for code unit info: 1. Type, 2. Name
c_html_s3_unit_info TYPE string VALUE
'<tr><td><samp>@1@</samp></td><td><dfn>@2@</dfn></td></tr>'.
* For section 4 - class components
CONSTANTS:
* Class name (as subsection header). 1. Clas/interf, 2. Name
c_html_s4_class_name TYPE string VALUE
'<h3>@1@ @2@</h3>',
* Header for components list
c_html_s4_components TYPE string VALUE
'<h4>Components:</h4>',
* Table line for general class info - program, base class and declar.
c_html_s4_class_program TYPE string VALUE
'<tr><td><samp>Program:</samp></td><td><dfn>@1@</dfn></td></tr>',
c_html_s4_class_base TYPE string VALUE
'<tr><td><samp>Base class:</samp></td><td><dfn>@1@</dfn></td></tr>',
c_html_s4_class_declaration TYPE string VALUE
'<tr><td><samp>Declaration:</samp></td><td><dfn>@1@</dfn></td></tr>',
* Table line for component summary info: 1. Type, 2. Name
c_html_s4_comp_sum_info TYPE string VALUE
'<tr><td><samp>@1@</samp></td><td><dfn>@2@</dfn></td></tr>'.
* For section 5 - non-class code units
CONSTANTS:
* Program name (as subsection header). 1. Name
c_html_s5_program TYPE string VALUE
'<h3>@1@</h3>'.
* For section 6 - code units calls hierarchy
* Prefix representing next level of nesting of include (like . )
CONSTANTS: c_html_s6_nesting_level TYPE string VALUE '. ',
* Style for placing: 1. Unit name, 2. Unit type
c_html_s6_unit TYPE string VALUE
'<dfn>@1@</dfn> <samp>@2@</samp><br>'.
*----------------------------------------------------------------------
* Program uses HTML keywords "A NAME" and "A HREF" (anchors) to build
* links to section describing refrenced objects. Anchors must have
* unique labels (IDs) within document. Program creates them
* in the following way (space is a separator in case of concatenation):
* - Programs (includes) - <program_name> (i.e. 'Z_INC_TEST')
* - Classes - 'Class definition' + <class_name>
* (i.e. 'Class definition ZCL_TEST')
* - Interfaces - 'Interface' + <interface_name>
* - Class/Interf. component - <comp_type> + <class_name> + <comp_name>
* (i.e. 'Data ZCL_TEST GV_CNT')
* - Other code units - <unit_type> + <name> (i.e. 'Form DO_TEST')
*----------------------------------------------------------------------*
* CLASS zcl_ic_code_analysis_html DEFINITION
*----------------------------------------------------------------------*
CLASS zcl_ic_code_analysis_html DEFINITION
INHERITING FROM zcl_ic_code_analysis.
PUBLIC SECTION.
* References to class handling writing HTML file
DATA: gr_html TYPE REF TO zcl_ic_html. " Ref to HTML object
* Writes results of analysis into HTML file. Must ne called after
* one of methods ANALYSE_xxx of base class.
* Parameters decide, which sections of analysis are written
* to the file.
METHODS: write_html_file IMPORTING
i_filename TYPE string
i_write_includes_hier TYPE c
i_write_includes_details TYPE c
i_write_class_components TYPE c
i_write_class_components_prot TYPE c
i_write_class_components_priv TYPE c
i_write_code_units_hier TYPE c
i_write_code_units_details TYPE c
i_write_tables TYPE c
i_html_comments TYPE c
RETURNING value(ret_code) TYPE i.
PRIVATE SECTION.
* Parameters from WRITE_HTML_FILE
DATA: lv_write_includes_hier TYPE c,
lv_write_includes_details TYPE c,
lv_write_code_units_hier TYPE c,
lv_write_code_units_details TYPE c,
lv_write_tables TYPE c,
lv_write_class_components TYPE c,
lv_write_class_components_prot TYPE c,
lv_write_class_components_priv TYPE c,
lv_html_comments TYPE c.
METHODS: do_write_comments IMPORTING is_comment TYPE ts_comment,
do_write_db_tables IMPORTING it_tables TYPE tt_dbtables,
do_write_db_tables_for_unit
IMPORTING i_clsname TYPE seoclsname
i_name TYPE t_unitname
i_type TYPE t_unittype,
do_write_comp_summary_single
IMPORTING is_cmp TYPE ts_classcmp,
do_write_comp_summary IMPORTING i_exp TYPE seoexpose
it_cmps TYPE tt_classcmps,
do_write_unit_details
IMPORTING i_name TYPE string
i_exp TYPE string
i_type TYPE string
i_label TYPE string
is_param TYPE ts_parameters
is_comment TYPE ts_comment,
do_write_details_class_comp
IMPORTING is_cmp TYPE ts_classcmp,
do_write_details_nonclass_unit
IMPORTING is_unit TYPE ts_modunit.
* Builds label for anchor for code unit. It can be used in 'a name'
* and 'a href' HTML tags.
METHODS: build_a_label_unit IMPORTING is_unit TYPE ts_modunit
EXPORTING e_label TYPE string,
build_a_label_class_name
IMPORTING i_clsname TYPE seoclsname
i_clstype TYPE seoclstype
EXPORTING e_label TYPE string,
build_a_label_class_comp IMPORTING is_cmp TYPE ts_classcmp
EXPORTING e_label TYPE string.
* Adds to HTML document string after replacing varaibles @n@ (n=1..3)
* with provided value.
METHODS: add_str_var IMPORTING
i_str TYPE string
i_value1 TYPE string OPTIONAL
i_value2 TYPE string OPTIONAL
i_value3 TYPE string OPTIONAL.
ENDCLASS. "zcl_ic_code_analysis_html DEFINITION
*----------------------------------------------------------------------*
* CLASS zcl_ic_code_analysis_html IMPLEMENTATION
*----------------------------------------------------------------------*
* Resets all atributes of the object.
METHOD reset.
CALL METHOD super->reset.
CLEAR: gr_html.
CLEAR: lv_write_includes_hier, lv_write_includes_details,
lv_write_class_components, lv_write_class_components_prot,
lv_write_class_components_priv,
lv_write_code_units_hier, lv_write_code_units_details,
lv_write_tables, lv_html_comments.
ENDMETHOD. "reset
* Writes results of analysis into HTML file. It must be called after
* one of methods ANALYSE_xxx.
METHOD write_html_file.
DATA: l_str TYPE string.
* Check if analysis has ben already performed
ret_code = 101.
CHECK gv_main_program_name IS NOT INITIAL.
* Store parameters in local atributes - to be used by other methods
lv_write_includes_hier = i_write_includes_hier.
lv_write_includes_details = i_write_includes_details.
lv_write_class_components = i_write_class_components.
lv_write_class_components_prot = i_write_class_components_prot.
lv_write_class_components_priv = i_write_class_components_priv.
lv_write_code_units_hier = i_write_code_units_hier.
lv_write_code_units_details = i_write_code_units_details.
lv_write_tables = i_write_tables.
lv_html_comments = i_html_comments.
* Start preparing HTML document (prepare heder)
CREATE OBJECT gr_html.
l_str = c_html_title.
REPLACE FIRST OCCURRENCE OF '@1@' IN l_str
WITH gv_main_program_name.
CALL METHOD gr_html->start_document
EXPORTING
i_title = l_str
i_code_page = c_html_code_page
i_css_file_name = c_css_file_name
i_comment = c_zicdoc_author.
* Section 0 - document title
CALL METHOD write_general_info.
* Section 1 - programs (includes) hierarchy
IF i_write_includes_hier IS NOT INITIAL.
CALL METHOD write_includes_hier.
ENDIF.
* Section 2 - access to database tables
IF i_write_tables IS NOT INITIAL.
CALL METHOD write_database_tables.
ENDIF.
* Section 3 - content of programs (includes)
IF i_write_includes_details IS NOT INITIAL.
CALL METHOD write_includes_details.
ENDIF.
* Section 4 - class components
IF i_write_class_components IS NOT INITIAL.
CALL METHOD write_class_components.
ENDIF.
* Section 5 - non-class code units
IF i_write_code_units_details IS NOT INITIAL.
CALL METHOD write_non_class_code_units.
ENDIF.
* Section 6 - hierarchy of code units calls
IF i_write_code_units_hier IS NOT INITIAL.
CALL METHOD write_code_units_hier.
ENDIF.
* Finish HTML document
CALL METHOD gr_html->end_document.
* Write HTML document to disk
ret_code = gr_html->write_file( i_filename ).
* Reset all atributes
CALL METHOD gr_html->reset.
CLEAR: gr_html.
* Write nested includes (hierarchy)
LOOP AT gt_programs INTO ls_prog.
* String representin depth of nesting (. . .)
CLEAR: l_out.
l_cnt = ls_prog-depth - 1.
DO l_cnt TIMES.
CONCATENATE l_out c_html_s1_nesting_level INTO l_out.
ENDDO.
* Program name. If details printed - place also HTML link
l_str = ls_prog-program.
IF lv_write_includes_details IS NOT INITIAL.
CALL METHOD gr_html->str_a_href
EXPORTING
i_label = l_str
i_text = l_str
RECEIVING
e_str = l_str.
ENDIF.
CONCATENATE l_out l_str INTO l_out.
CALL METHOD add_str_var
EXPORTING
i_str = c_html_s1_program_name
i_value1 = l_out.
ENDLOOP.
ENDMETHOD. "write_includes_hier
* Section 2 - access to database tables.
METHOD write_database_tables.
DATA: lt_tables TYPE tt_dbtables,
ls_table TYPE ts_dbtable,
ls_last TYPE ts_dbtable.
* Table GT_DBTABLES can contains the same table in several records
* for instance, access from different forms. Therefore, we need
* to prepare unique record only.
SORT gt_dbtables BY table mode.
LOOP AT gt_dbtables INTO ls_table.
IF ls_table-name <> ls_last-name AND
ls_table-mode <> ls_last-mode.
APPEND ls_table TO lt_tables.
ls_last = ls_table.
ENDIF.
ENDLOOP.
* At least one record
CHECK lt_tables IS NOT INITIAL.
DATA: lt_tables TYPE tt_dbtables,
ls_table TYPE ts_dbtable.
* Prepare list of tables for code unit
LOOP AT gt_dbtables INTO ls_table WHERE clsname = i_clsname
AND name = i_name
AND type = i_type.
APPEND ls_table TO lt_tables.
ENDLOOP.
* At least one record
CHECK lt_tables IS NOT INITIAL.
* Write list of tables
CALL METHOD do_write_db_tables( lt_tables ).
ENDMETHOD. "do_write_db_tables_for_unit
* Section 3 - content of INCLUDEs (summary).
METHOD write_includes_details.
DATA: ls_prog TYPE ts_program,
ls_unit TYPE ts_modunit.
DATA: l_str TYPE string,
l_str2 TYPE string,
l_str3 TYPE string,
l_label TYPE string.
* Program title (in a table)
IF ls_prog-title IS NOT INITIAL.
l_str = ls_prog-title.
CALL METHOD add_str_var
EXPORTING
i_str = c_html_s3_title
i_value1 = l_str.
ENDIF.
* Program comments
CALL METHOD do_write_comments( ls_prog-comment ).
* Code units list header
CALL METHOD gr_html->add_string_raw( c_html_s3_units ).
CALL METHOD gr_html->flush_buffer.
* Write code units in HTML table
gr_html->add_tag_start( 'table' ).
CALL METHOD gr_html->flush_buffer.
* All code units for current program
LOOP AT gt_modunits INTO ls_unit WHERE program = ls_prog-program.
* If details for code units or class components are issued
IF ( ls_unit-type = 'M' OR ls_unit-type = 'I' OR
ls_unit-type = 'CD' OR ls_unit-type = 'CI' ) AND
lv_write_class_components IS NOT INITIAL OR
lv_write_code_units_details IS NOT INITIAL.
DATA: lt_cmps TYPE tt_classcmps,
ls_cmp TYPE ts_classcmp.
DATA: ls_prog TYPE ts_program,
ls_class TYPE ts_class,
* ls_param TYPE ts_param_detail,
l_type TYPE t_unittype,
l_str TYPE string, l_str2 TYPE string, l_str3 TYPE string.
* Write general info in HTML table
gr_html->add_tag_start( 'table' ).
CALL METHOD gr_html->flush_buffer.
* Base class
IF ls_class-super IS NOT INITIAL.
l_str2 = ls_class-super.
* If we have base class in tables components - build reference
READ TABLE gt_classes TRANSPORTING NO FIELDS
WITH KEY clsname = ls_class-super
clstype = '0'.
IF sy-subrc = 0.
CALL METHOD build_a_label_class_name
EXPORTING
i_clsname = ls_class-super
i_clstype = '0'
IMPORTING
e_label = l_str3.
CALL METHOD gr_html->str_a_href
EXPORTING
i_label = l_str3
i_text = l_str2
RECEIVING
e_str = l_str2.
ENDIF.
CALL METHOD add_str_var
EXPORTING
i_str = c_html_s4_class_base
i_value1 = l_str2.
ENDIF.
* Class declaration
IF ls_class-param-text is not INITIAL.
CALL METHOD add_str_var
EXPORTING
i_str = c_html_s4_class_declaration
i_value1 = ls_class-param-text.
ENDIF.
* READ TABLE ls_class-param-params INTO ls_param INDEX 1.
* IF sy-subrc = 0.
*
* l_str = ls_param-text.
* CALL METHOD add_str_var
* EXPORTING
* i_str = c_html_s4_class_declaration
* i_value1 = l_str.
* ENDIF.
* Program name
l_str = ls_class-program.
IF lv_write_includes_details IS NOT INITIAL.
CALL METHOD gr_html->str_a_href
EXPORTING
i_label = l_str
i_text = l_str
RECEIVING
e_str = l_str.
ENDIF.
CALL METHOD add_str_var
EXPORTING
i_str = c_html_s4_class_program
i_value1 = l_str.
* Close general info
gr_html->add_tag_end( 'table' ).
CALL METHOD gr_html->flush_buffer.
* Class comments
CALL METHOD do_write_comments( ls_class-comment ).
* Prepare local table with comp. belonging to the current class
REFRESH: lt_cmps.
LOOP AT gt_classcmps INTO ls_cmp
WHERE clsname = ls_class-clsname
AND clstype = ls_class-clstype.
APPEND ls_cmp TO lt_cmps.
ENDLOOP. " components
* Components summary list header
CALL METHOD gr_html->add_string_raw( c_html_s4_components ).
CALL METHOD gr_html->flush_buffer.
* Write components summary in HTML table
gr_html->add_tag_start( 'table' ).
CALL METHOD gr_html->flush_buffer.
* Write public components
CALL METHOD do_write_comp_summary
EXPORTING
i_exp = '2'
it_cmps = lt_cmps.
* Write protected components
IF lv_write_class_components_prot IS NOT INITIAL.
CALL METHOD do_write_comp_summary
EXPORTING
i_exp = '1'
it_cmps = lt_cmps.
ENDIF.
* Write private components
IF lv_write_class_components_priv IS NOT INITIAL.
CALL METHOD do_write_comp_summary
EXPORTING
i_exp = '0'
it_cmps = lt_cmps.
ENDIF.
* For methods - write additional info
CHECK is_cmp-cmptype = 'M' OR is_cmp-cmptype = 'CM'.
* Methods can have additional comments in implementation section.
* These commenta are not in table of class components, but in
* code units.
READ TABLE gt_modunits INTO ls_unit
WITH KEY name = is_cmp-cmpname
type = 'M'
clsname = is_cmp-clsname.
IF sy-subrc = 0.
CALL METHOD do_write_comments( ls_unit-comment ).
ENDIF.
* Units defined in the program
LOOP AT gt_modunits INTO ls_unit
WHERE program = ls_prog-program.
* Skip some unit types (related to classes - they are displayed
* in dedicated section
CHECK ls_unit-type <> 'CD' AND ls_unit-type <> 'I' AND
ls_unit-type <> 'M'.
* Details of code unit
CALL METHOD do_write_details_nonclass_unit( ls_unit ).
ENDLOOP. " units
ENDLOOP. " programs
ENDMETHOD. "write_code_units_details
* Writes details of single non-class code unit.
METHOD do_write_details_nonclass_unit.
DATA: l_str1 TYPE string,
l_str2 TYPE string,
l_str3 TYPE string.
* Section 6 - hierarchy of code units calls (functions, forms, ...).
METHOD write_code_units_hier.
DATA: ls_hier TYPE ts_unitshier,
ls_unit TYPE ts_modunit.
DATA: l_str TYPE string, l_str2 TYPE string, l_str3 TYPE string,
l_out TYPE string.
DATA: l_cnt TYPE i.
* Process the following calls
LOOP AT gt_unitshier INTO ls_hier.
* String representin depth of nesting (. . .)
CLEAR: l_out.
l_cnt = ls_hier-depth - 1.
DO l_cnt TIMES.
CONCATENATE l_out c_html_s6_nesting_level INTO l_out.
ENDDO.
l_str = get_code_unit_type_desc( ls_hier-type2 ).
l_str2 = ls_hier-name2.
* At the moment - no reference for methods (we don't know
* called class name)
IF lv_write_code_units_details IS NOT INITIAL AND
ls_hier-type2 <> 'M'.
* Check if we have details of called unit
READ TABLE gt_modunits TRANSPORTING NO FIELDS
WITH KEY name = ls_hier-name2 type = ls_hier-type2.
IF sy-subrc = 0.
* Create label for anchor
CLEAR: ls_unit.
ls_unit-name = ls_hier-name2.
ls_unit-type = ls_hier-type2.
CALL METHOD build_a_label_unit
EXPORTING
is_unit = ls_unit
IMPORTING
e_label = l_str3.
CALL METHOD gr_html->str_a_href
EXPORTING
i_label = l_str3
i_text = l_str2
RECEIVING
e_str = l_str2.
ENDIF.
ENDIF.
CONCATENATE l_out l_str2 INTO l_out.
CALL METHOD add_str_var
EXPORTING
i_str = c_html_s6_unit
i_value1 = l_out
i_value2 = l_str.
ENDLOOP.
ENDMETHOD. "write_code_units_hier
* Writes details of single code unit. Details should be passed as
* strings (no further processing is performed on them).
METHOD do_write_unit_details.
DATA: ls_param TYPE ts_param_detail.
DATA: l_str TYPE string, l_str2 TYPE string.
* Header of code unit - name must be 'a name'
CALL METHOD gr_html->str_a_name
EXPORTING
i_label = i_label
i_text = i_name
RECEIVING
e_str = l_str.
CALL METHOD add_str_var
EXPORTING
i_str = c_html_unit_det_header
i_value1 = l_str.
* For class components, concatenate exposure (ie. Public) with
* component type (ie. Method).
l_str2 = i_type.
IF i_exp IS NOT INITIAL.
CONCATENATE i_exp i_type INTO l_str2 SEPARATED BY space.
ENDIF.
* Prepare string with parameters (declaration)
* CLEAR: l_str.
* READ TABLE is_param-params INTO ls_param INDEX 1.
* IF sy-subrc = 0.
* l_str = ls_param-text.
* ENDIF.
* If tag is INFO, it is printed directly as definition
IF ls_tag-tag = 'INFO'.
CALL METHOD gr_html->add_tag
EXPORTING
tag = 'dd'
str = l_str3.
ELSE.
* For other tags - write full info
CALL METHOD add_str_var
EXPORTING
i_str = c_html_comment_complex
i_value1 = l_str1
i_value2 = l_str2
i_value3 = l_str3.
ENDIF.
ENDLOOP.
* Close dictionary
gr_html->add_tag_end( 'dl' ).
CALL METHOD gr_html->flush_buffer.
ENDMETHOD. "do_write_comments
* Builds label for anchor for code unit. It can be used in 'a name' and
* 'a href' HTML tags.
METHOD build_a_label_unit.
DATA: l_type TYPE t_unittype.
DATA: l_typestr TYPE string.
l_type = is_unit-type.
* Class implementation change to class definition
IF l_type = 'CI'.
l_type = 'CD'.
ENDIF.
l_typestr = get_code_unit_type_desc( l_type ).
* For methods we must include class name in an anchor
IF l_type = 'M'.
CONCATENATE l_typestr is_unit-clsname is_unit-name INTO e_label
SEPARATED BY space.
ELSE.
CONCATENATE l_typestr is_unit-name INTO e_label
SEPARATED BY space.
ENDIF.
ENDMETHOD. "build_a_label_unit
* Builds label for anchor for class definition or interface.
* It can be used in 'a name' and 'a href' HTML tags.
METHOD build_a_label_class_name.
DATA: l_type TYPE t_unittype.
DATA: l_typestr TYPE string.
CONCATENATE l_typestr i_clsname INTO e_label SEPARATED BY space.
ENDMETHOD. "build_a_label_class_name
* Builds label for anchor for class component.
* It can be used in 'a name' and 'a href' HTML tags.
METHOD build_a_label_class_comp.
DATA: l_typestr TYPE string.
l_typestr = get_class_cmp_type_desc( is_cmp-cmptype ).
CONCATENATE l_typestr is_cmp-clsname is_cmp-cmpname INTO e_label
SEPARATED BY space.
ENDMETHOD. "build_a_label_class_comp
* Adds to HTML document string after replacing varaibles @n@ (n=1..3)
* with provided value.
METHOD add_str_var.
DATA: str TYPE string.
str = i_str.
REPLACE ALL OCCURRENCES OF '@1@' IN str WITH i_value1.
REPLACE ALL OCCURRENCES OF '@2@' IN str WITH i_value2.
REPLACE ALL OCCURRENCES OF '@3@' IN str WITH i_value3.
CALL METHOD gr_html->add_string_raw( str ).
CALL METHOD gr_html->flush_buffer.
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
All product names are trademarks of their respective companies. SAPNET.RU websites are in no way affiliated with SAP AG. SAP, SAP R/3, R/3 software, mySAP, ABAP, BAPI, xApps, SAP NetWeaver and any other are registered trademarks of SAP AG. Every effort is made to ensure content integrity. Use information on this site at your own risk.